剑指offer67_剪绳子_题解
剪绳子
题目描述
给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为k[1],...,k[m]。请问k[1]x...xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
输入描述:
输入一个数n,意义见题面。(2 <= n <= 60)
返回值描述:
输出答案。
示例1
输入
8
返回值
18
分析
方案一:记忆化递归
每次将一段绳子剪成两段时,剩下的部分可以继续剪,也可以不剪
- \(i*cuttingRope(n-i)\) 表示继续剪
- \(i*(n-i)\)表示不继续剪
求乘积最大值即取比较剪与不剪二者的乘积最大值
代码
/*
1.时间复杂度:O(n^2)
2.空间复杂度:O(n)
*/
class Solution
{
public:
int memo[60] = {0};
int cutRope(int n)
{
if (n == 2)
return 1;
if (memo[n] != 0)
return memo[n];
int ret = -1;
// 每次将一段绳子剪成两段时,剩下的部分可以继续剪,也可以不剪
for (int i = 1; i < n; ++i)
ret = max(ret, max(i * (n - i), i * cutRope(n - i)));
memo[n] = ret;
return ret;
}
};
方案二:动态规划
设 \(dp[i]\) 表示将正整数 \(i\) 拆分成至少两个正整数的和之后,这些正整数的最大乘积。
-
初始状态:\(dp[2]=1\)
-
状态转移方程:
\[dp[i] = max(dp[i], max(j*(i-j), j*dp[i-j])) \tag{1<=j<=i} \] -
返回值:\(dp[n]\)
代码
/*
1.时间复杂度:O(n^2)
2.空间复杂度:O(n)
*/
class Solution
{
public:
int cutRope(int n)
{
vector<int> dp(n + 1);
for (int i = 2; i <= n; ++i)
{
int curMax = 0;
for (int j = 1; j < i; ++j)
{
curMax = max(curMax, max(j * (i - j), j * dp[i - j]));
}
dp[i] = curMax;
}
return dp[n];
}
};