版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/littlehaes/article/details/91411165
welcome to my blog
剑指offer面试题14(java版):剪绳子
题目描述
给你一根长为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
思路
- 动态规划: 注意子问题和子子问题的关系, 比如:我们把长为3的绳子剪成1,2或者2,1两种, 而不考虑1,1,1这种情况, 也就是只剪一次
动态规划求解的问题的特点
- 求一个问题的最优解
- 整体问题的最优解依赖各个子问题的最优解
- 把大问题分解成若干个小问题, 这些小问题之间还有相互重叠的更小的子问题
- 从上往下分析问题,从下往上求解问题
复杂度
时间复杂度: O(n^2)
空间复杂度: O(n)
public static int maxProductAfterCutting_solution(int length){
if(length < 2) // 长度小于2没法切. 长度为1的绳子没法切;但是某个绳子切完后可以包含长为1的绳子,注意这二者的区分
return 0;
if(length==2)
return 1;
if(length==3)
return 2;
// products的索引为1,2,3时只是表示绳子长度为1,2,3
// products的索引i大于3时,表示长为i的绳子剪切后各段乘积能得到的最大值
int[] products = new int[length+1]; // 长度加一后,最后一个索引是length, 方便表示
products[1] = 1;
products[2] = 2;
products[3] = 3;
for(int i=4; i<=length; i++){
// for(int j=1; j<=i-1; j++){ //长为i的绳子,切割位置可以是{1,2,3,...i-1}
for(int j=1; j<=i/2; j++){ // 长为3的绳子,可以切成1,2; 2,1; 效果是一样的,所以只用切i/2次就行 // 可能要问不是还能切成1,1,1这种吗? 为什么只切1次? 1,1,1这种情况在1,2中已经考虑过了,1,1是2的两个子问题. 这里要明确子问题与更小的子问题的关系
if(products[i] < products[j]*products[i-j])
products[i] = products[j]*products[i-j];
}
}
return products[length];
}