题目:
给你一段绳子,这段绳子的长度是正整数(绳子长度大于0),你可以选择切或者不切,如果切,分成两段,保证两段的长度都是整数,如果可以继续切,你可以选择继续,最后要求每一段绳子的长度的乘积最大。
思考一:
如果每次从中间切似乎得到的乘积会很大,那么当绳子长度为偶数,就直接从中间切,如果是奇数,那么奇数加1或者减1后再二分的位置切。
static int clacLen(int n) {
if(n<=0) {
return 0;
} else if(n==1){
return 1;
} else if(n==2) {
return 2;
} else if(n==3){
return 3;
} else {
if(n % 2 ==0) {
return Test.clacLen(n/2)*Test.clacLen(n/2);
} else {
return Test.clacLen((n-1)/2)*Test.clacLen((n+1)/2);
}
}
}
| 输入 | 输出 |
| 5 | 6 |
| 6 | 9 |
| 7 |
12 |
| 8 | 16 |
输入5,6,7结果是对的,但是8就不对了,因为如果8拆分为3,3,2后,绳子长度乘积将是18。
思考2:
从思考1中可以发现,不仅仅要均分绳子,而且要保证在均分的条件下每一段的绳子长度最长,所有分到最后的结果是2或者3,如果能保证切分过程中得到更多的长度为3的绳子,那么就能保证每段绳子乘积最大。
static int clacLenEnhance(int n) {
if(n<=0) {
return 0;
} else if(n>0 && n<5){
return n;
} else {
return Test.clacLenEnhance(3)*Test.clacLenEnhance(n-3);
}
}
采用递归算法,每次取一个3出来,这样就能保证最后绳子的长度乘积最大。这种思路就是用到了贪心算法:贪心选择是指所求问题的整体最优解可以通过一系列局部最优的选择。
| 输入 | 输出 |
| 5 | 6 |
| 6 | 9 |
| 7 | 12 |
| 8 | 18 |
思考3:
思考2看上去解题思路非常简单,但是要能迅速找到局部最优解是非常难得一件事件。怎么样在思考1的基础上能优化呢,还是采用二分法的思路,但是每做一步都要进行决策,选出每一步里面最优的解。
static int clacLenDP(int n) {
if(n<=0) {
return 0;
} else if(n>0 && n<5){
return n;
} else {
int [] array = new int[n+1];
array[0]=0;
array[1]=1;
array[2]=2;
array[3]=3;
array[4]=4;
int max = 0;
for(int i=5; i<=n; i++){
max = 0;
for(int j=1; j<=i/2; j++){
int temp = array[j]*array[i-j];
if(temp>max){
max=temp;
array[i]=max;
}
}
}
System.out.println("----------------------------");
for(int k=0; k<=n; k++){
System.out.println(array[k]);
}
return array[n];
}
}
这次我们仅仅看看输入8的时候,最终把数组的每个值打印出来的结果
----------------------------
0
1
2
3
4
6
9
12
18
18
发现规律了吗?这个数组的每个值竟然是该值对应的数组下标作为绳子长度的时候的最长乘积。这里用到的就是动态规划算法,后面每一步都是基于前面每一步的结果,二者之间是有联系的。如果不明白,可以给大家推算下,当 i=8 之前,数组就存储了下面这些值:
----------------------------
array[0] 0
array[1] 1
array[2] 2
array[3] 3
array[4] 4
array[5] 6
array[6] 9
array[7] 12
当 i=8 的时候,在第2层for循环会做如下计算
a1*a7 1*12
a2*a6 2*9
a3*a4 3*4
a4*a4 4*4
最终max选择的 2*9 = 18 作为 array[8] 的值。
总结:
今天讲了三种解法,两种算法,第一种解法是错误的,大家一定要注意。希望大家记住的是两种算法,在做算法题的时候优先考虑用这两种算法解题。
1196

被折叠的 条评论
为什么被折叠?



