方法一:自下而上动态规划 + 记忆化:两个循环
class Solution {
public:
int cuttingRope(int n) {
if(n <= 3) return n - 1; // 当绳子的总长度<=3时,做特殊情况处理
//长度<=3时 必须要剪 所以会小 但是一旦>3就不用动长度3以下的绳子了
vector<int> res(n + 1, 0); // res[i]表示长度为i的绳子剪成若干段之后,乘积的最大值
// 特殊处理:如果某个长度的绳子,剪了一下之后,其中一段的长度在[0,3]的区间内,就不要再剪这一段了
// 因为剪了之后,乘积会变小,而res[i]是长度为i的绳子剪成若干段后能获得的最大乘积
// 所以[res[0],res[3]]要单独处理(如下)
res[0] = 0;
res[1] = 1;
res[2] = 2;
res[3] = 3;
int maxProduct = 0;
for(int i=4; i<=n; ++i)
{
// maxProduct = 0;
for(int j=1; j<=i/2; ++j)//注意这里的范围
{
// 循环体中写i/2是为了减少计算次数(因为比如1x3和3x1值是一样的,计算一次即可)
int temp = res[j] * res[i-j];//注意这里
maxProduct = getMax(maxProduct, temp);
res[i] = maxProduct; // res数组是做记忆化处理用的
}
}
return res[n];
}
int getMax(int a, int b)
{
return a >= b ? a : b;
}
};
作者:superkakayong
链接:https://leetcode-cn.com/problems/jian-sheng-zi-lcof/solution/zi-jie-ti-ku-jian-14-i-zhong-deng-jian-sheng-zi-1s/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution {
public:
int cuttingRope(int n) {
if(n <= 3) return n - 1;
int res = 0, count3 = n / 3;
if(n % 3 == 0) return pow(3, count3);
else if( n % 3 == 1)
{
count3 --;
return pow(3, count3) * 4;
}
else return pow(3, count3) * 2;
}
};
作者:superkakayong
链接:https://leetcode-cn.com/problems/jian-sheng-zi-lcof/solution/zi-jie-ti-ku-jian-14-i-zhong-deng-jian-sheng-zi-1s/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
- 其实res数组求的是绳子长度大于等于3的时候的,因为代码的第一行就已经给出了绳子长度小于等于3时能剪出的最大长度了。所以res[3]应该等于3,原因是当绳子长度大于等3时(比如4),每当剪了一次之后,某一部分的长度在[0,3]之间,我们就不应该再剪这一部分了,因为剪了会使得这一部分的乘积变小(比如长度为3,不剪的话它就是3,剪了的话就是1*2=2,2<3,不划算)。
- 至于为啥 vector 中是 n+1 个元素,因为这样比较方便我们计算。设为 n+1 个元素的话,res[n] 表示的就是长度为 n的绳子能剪出的最大长度了,不然的话得是 res[n-1] 才能表示,就会有点乱。
左神说在笔试中不会使用贪心算法 因为只要找到了贪心策略代码很简单 但是贪心策略很难找,所以没有看贪心的解法