【剑指 Offer 14- I. 剪绳子 中等】【343. 整数拆分 中等】【剑指 Offer 14- II. 剪绳子 II 中等】
【剑指 Offer 14- I. 剪绳子 中等】【343. 整数拆分 中等】
给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]...k[m-1] 。请问 k[0]*k[1]*...*k[m-1] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1
示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36
给定一个正整数 n,将其拆分为至少两个正整数的和,并使这些整数的乘积最大化。 返回你可以获得的最大乘积。
示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1。
示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36。
说明: 你可以假设 n 不小于 2 且不大于 58。
2. 使用动态规划
dp[i]:长度为i的绳子切为m段得到的最大乘积
先切一刀,这一刀切下的长度从2到 i- 1,如果后面的不切了,乘积为j*(i - j),如果后面的继续切,那么乘积为j*dp[i - j].
class Solution { public: int integerBreak(int n) { vector<int> dp(n + 1); dp[2] = 1; for(int i = 3; i <= n; i++) { for(int j = 2; j <= i - 1; j ++) { dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j])); } } return dp[n]; } };
时间复杂度更低的基于数学推导或者贪心算法推导的解法可参照LeetCode大佬的题解:https://leetcode-cn.com/problems/jian-sheng-zi-lcof/solution/mian-shi-ti-14-i-jian-sheng-zi-tan-xin-si-xiang-by/
结论是:当平均分段,且每段长为3时乘积最大。
因此设:b = n % 3,b为0,1,2。b为0和2的时候没什么可说的,当b为1时:2*2 > 3*1,因此应当拆分出一个3,和1组成4。
class Solution { public: int integerBreak(int n) { if(n <= 3) return n - 1; int res = 0; int a = n / 3; int b = n % 3; if(b == 0) res = pow(3, a); else if(b == 1) res = pow(3, a - 1) * 4; else res = pow(3, a) * 2; return res; } };
【剑指 Offer 14- II. 剪绳子 II 中等】
在上题的基础上,扩大了求取范围导致要对结果求模,否则会越界。这里用到了循环求模的方法,基于公式:( x * y ) % a = (x%a * y%a) % a,因此:(xn)%a = (xn-1%a * x)%a
class Solution { public: long powMode(long x, long a, long k) { long res = 1; for(int i = 0 ; i < a; i++) { res = (res % k * x) % k; } return res; } int cuttingRope(int n) { if(n <= 3) return n - 1; modeBase = 1000000007; int a = n / 3, b = n % 3; long res = powMode(3, a - 1, modeBase); if(b == 0) res = (res * 3) % modeBase; else if(b == 2) res = (res * 6) % modeBase; else res = (res * 4) % modeBase; return res; } private: int modeBase; };