题目描述
https://leetcode-cn.com/problems/jian-sheng-zi-lcof/
(leetcode14)
给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],…,k[m]。请问k[0]xk[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
输入描述:
输入一个数n,意义见题面。(2 <= n <= 60)
示例1
输入
8
输出
18
解析:
一.确定状态
动态规划问题,自顶向下思考,自底向上实现,所以考虑实现的最后一步即可得到状态转移方程.
①最后一步
- 最优策略一定是长度为n的绳子分成m段的乘积最大
- 一定有最后一段绳子长度为i
- 除掉这一段绳子,剩下的绳子长度为(n-i)
- (n-i)的长度的绳子分段后乘积最大
②子问题
- (n-i)长度的绳子分成k段的乘积最大
- 原问题是长度为n的绳子分成m段的乘积最大
- 状态:f(x)=长度为x的绳子分成y段后乘积最大
- 最后一段的长度是未知的,但是只能是[1-x-1]
二.转移方程
f(i) = max(j*f(i-j)) (j为1到i-1)
三.初始条件和边界条件
①初始条件:f[0]=0,f[1]=1,f[2]=2,f[3]=3
②边界条件: 如果绳子长度小于4需要直接得到结果 (因为在参与计算的时候,可以不对另一部分进行分段)
这里需要注意: 因为这种方法已经默认至少分为两段,所以求解f(i) = max(j*f(i-j))时f(i-j)可以不分段,所以要找到分段与不分段的最大乘积相同的那个长度作为起始长度x,小于x的长度直接给出结果,大于x的长度计算得到,所以它的数组初始化到长度为3时,长度为3时不分段最长.
四.计算顺序
从小到大.当计算f[6]时,f[4]f[5]都已经计算出来了.
Solution1:
class Solution {
public:
int cutRope(int number) {
if(number<2) return 0;
if(number == 2) return 1;
if(number == 3) return 2;
int *products = new int[number+1]{0};
products[0] = 0;
products[1] = 1;
products[2] = 2;
products[3] = 3;
for(int i=4;i<=number;i++)
{
for(int j=1;j<i;j++)
{
products[i] = max(products[i],j*products[i-j]);
}
}
return products[number];
}
};
2020/4/9补充:
剪绳子2
题目描述:
给你一根长度为 n 的绳子,请把绳子剪成整数长度的 m 段(m、n都是整数,n>1并且m>1),每段绳子的长度记为 k[0],k[1]…k[m] 。请问 k[0]k[1]…*k[m] 可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。
答案需要取模 1e9+7(1000000007),如计算初始结果为:1000000008,请返回 1。
https://leetcode-cn.com/problems/jian-sheng-zi-ii-lcof/
题目解析:
考虑数据爆炸问题,采用贪心算法。当n小于4时直接返回,当n大于4时考虑它切出一段为m,当m小于4时它是不用再切分的,当m为3时为最大不切分值,所以以3为分界值进行切割。
Solution:
class Solution {
public:
int cuttingRope(int n) {
const int inf = 1e9+7;
if(n<2) return 0;
if(n == 2) return 1;
if(n == 3) return 2;
long long ans = 1;
while(n>4)
{
ans = (ans*3)%inf;
n = n-3;
}
return (ans*n)%inf;
}
};