343. Integer Break
问题:
将给定正整数n,拆成多个数。(使得这些数之和=n)
这些数之积最大是多少。
Example 1: Input: n = 2 Output: 1 Explanation: 2 = 1 + 1, 1 × 1 = 1. Example 2: Input: n = 10 Output: 36 Explanation: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36. Constraints: 2 <= n <= 58
解法:DP,math
解法一:DP
- 状态:dp[n]:n被拆分后所得最大乘积
- 要被拆分的数 n
- 选择:
- 拆出去x=1~n-1中任意数,和剩下的数n-x,被拆分后的最大乘积,相乘所得结果中的最大值。
- MAX {(x:1~n-1)
- dp[n-x] * x
- }
- base:
- dp[1]=1
- dp[2]=1
⚠️ 注意:当得到 当前数 n 的拆分最大结果 dp[n] 后,
为求解后面的数 >n ,n 自己也可作为乘数,不拆分,因此dp[n] = max(n,dp[n]),用 自己 和 刚才求得结果dp[n] 之间,再求最大值。
代码参考:
1 class Solution { 2 public: 3 //dp[n]:maximum product of divide n. 4 //opt: MAX:(x=1~n-1) 5 // = dp[n-x] * x 6 //base: 7 //dp[1]=1 8 //dp[2]=1 9 int integerBreak(int n) { 10 vector<int> dp(n+1,0); 11 int res = 0; 12 dp[1]=1; 13 dp[2]=1; 14 for(int i=3; i<=n; i++) { 15 dp[i-1] = max(i-1, dp[i-1]); 16 //i-1: as itself(not to divide) -> for other element calculate. 17 for(int x=2; x<=i-1; x++) { 18 dp[i] = max(dp[i], dp[i-x]*x); 19 } 20 } 21 return dp[n]; 22 } 23 };
解法二:math
思路:要使 拆分n 的乘积取得最大。
我们先考虑,将 n 拆分为两个数 f=x(N-x) (以后在递归拆分这两个数即可)
怎么样才能使得 f 最大,可得:
x=N/2,我们能得到最大。
由于根据题意,我们需要拆分成两个正整数。那么分奇偶性讨论:
- N为偶数:(N/2)*(N/2)
- N为奇数:((N+1)/2) * ((N-1)/2)
要使其结果>=N
那么可得:
- N为偶数:N>=4
- N为奇数:N>=5
也就是说,只要N>=4,都可被拆分成两个更小的数,使得乘积更大。
那么,能作为乘积的数只有:1,2,3
- 1*任何数都不能变大,因此排除 1
- 只能在2 和 3 中选择拆分因数。
- 我们优先选择3,理由是:
- 例如 N=6,
- 3*3>2*2*2
- 我们选择先拆分为3,能得到选择2更大的结果。
- 我们优先选择3,理由是:
总结:
我们对N>=4的数可进行优先拆分出3,循环拆分,
直到拆分不出来3,就其次选择2。
⚠️ 注意,要排除最终拆出个 1 的情况,这样只会削减结果。
例如,4->
先拆分 3 的话,剩下一个 1。因此我们不能选择这种拆法
其次选择拆分 2,再留下个 2。选择这种拆分法。
代码参考:
1 class Solution { 2 public: 3 int integerBreak(int n) { 4 if(n==2) return 1; 5 if(n==3) return 2; 6 int product = 1; 7 while(n>4) { 8 product *= 3; 9 n-=3; 10 } 11 product *= n; 12 return product; 13 } 14 };