正の整数 n が与えられたとき、それを少なくとも2つの正の整数の和に分割し、それらの整数の積を最大化しなさい。 得られる最大の積を返しなさい.
例題:
- 例1
 : 2
 : 1
 : 2 = 1 + 1, 1 × 1 = 1 
- 例2
 : 10
 : 36
 :  + 4, 3 × 3 × 4 = 36 
内容:
nは2以上58以下と仮定してください。
推論
n個の数字に分割され、nは固定されていない このタイプの問題:ルールは確実、開始条件は不確定。
- 動的計画法
- 再帰
動的計画法
nを列挙し、dpは異なるnの結果値を記録し、dp[n]はクエリー結果:
- 分割する整数の数を決定:<=i<=n2<=i<=n
- dp[i]はiで分割された整数の積の最大値。- 2つ以上のj,dp[i - j]を分割 -> dp[i - j]は2つ、つまりより多くの部分集合を分割
- 2つのjの分割,i-j
 
/**
 * @param {number} n
 * @return {number}
 */
var integerBreak = function (n) {
 let dp = Array(n + 1).fill(1)
 for (let i = 2; i <= n; i++) {
 let curMax = 0
 for (let j = 1; j < i; j++) {
 curMax = Math.max(curMax, Math.max(j * (i - j), j * dp[i - j]))
 }
 dp[i] = curMax
 }
 return dp[n]
}
再帰
- パラメータで分割する整数を指定します。
- 終了条件:- 既に分割された配列に遭遇した場合
 
再帰のロジックは基本的にダイナミック・プログラミングと同じです:
- 数字jを分割
- i-jに属する数字は、単独で数字として成り立つことも、分割され続けることもできます。
/**
 * @param {number} n
 * @return {number}
 */
var integerBreak = function (n) {
 let dp = Array(n + 1).fill(1)
 function dfs(n){
 if (dp[n]) return dp[n];
 let curMax = 0;
 for (let i = 1; i < n; i++) {
 curMax = Math.max(curMax, i * (n - i), i * dfs(n - i));
 }
 return dp[n] = curMax;
 };
 return dp[n]
}
最適化された動的計画法
/**
 * @param {number} n
 * @return {number}
 */
var integerBreak = function (n) {
 if (n < 4) return n - 1;
 let dp = Array(n + 1).fill(1)
 for (let i = 3; i <= n; i++) {
 dp[i] = Math.max(Math.max(2 * (i - 2), 2 * dp[i - 2]), Math.max(3 * (i - 3), 3 * dp[i - 3]));
 }
 return dp[n];
}
ブログ:
出版:The Pit's Little Bookie





