题目描述

给你一根长度为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,这时候长length与宽width在什么情况下,达到面积s最大
s = length width
设length = x
则:width = n/2 - x
所以 s = x
(n/2 - x)
= -x^2 + nx/2
求导s’ = -2x + n/2
s’ = 0 —> 得 x = n/4
(0,n/4)区间,s’>0,S单调递增
(n/4, n)区间,s’<0,S单调递减
n/4为极大值点
所以在长度x=n/4的时候,S的面积最大
width = n/2 - x
= n/2 - n/4
= n/4
所以width = length 的时候 s最大
通过一般性问题得出当定长的时候,截出的子段长度相等的时候,乘积最大
(通用性待数学求证)
回到本题
绳子长度为n,分成m分,那先设每分长度为x, 分数m=n/x
那么结果就是 n/x个 x 相乘 f(x)=x^(n/x)
求导:如下图
66 剪绳子 - 图1
所以问题就回到了n/3的个数上面
当n能被3整除的时候,乘积=n^(n/3)
当n除3余1的时候,这时候发现多了一个1,这个1是不是很鸡肋,但是把前面的一个3拿出来,把这个一个1和前面一个3 分解为2和2,就变大了,所以乘积为 3^(n/3 - 1)
4
当n除3余2的时候,乘积为n^(n/3) * 2

代码一

  1. public int cutRope(int target) {
  2. if(target<3)return target;
  3. if(target==3)return 2;
  4. int m = target%3;
  5. switch(m){
  6. case 0:
  7. return (int) Math.pow(3, target/3);
  8. case 1:
  9. return (int)Math.pow(3, target/3-1)*4;
  10. case 2:
  11. return (int)Math.pow(3, target/3)*2;
  12. }
  13. return 0;
  14. }

代码二

思路:
递归 自顶向下
我们先定义函数f(n)为把绳子剪成若干段之后的各段长度乘积的最大值.在剪第一刀的时候,我们会有n-1种可能的选择,也就是说剪出来的第一段绳子的长度可能为1,2,……n-1.因此就有了递归公式 f(n) = max(f(i)*f(n-i)),其中0<i<n.

  1. public int cutRope(int target) {
  2. if(target<2)return 0;
  3. if(target==2)return 1;
  4. if(target==3)return 2;
  5. return ItercutRope(target);
  6. }
  7. public int ItercutRope(int target) {
  8. int max = 0;
  9. for(int i = 0;i<target/2+1;i++) {
  10. max = Math.max(ItercutRope(i)* ItercutRope(target-i),max);
  11. }
  12. return max;
  13. }

代码三

思路:动态规划 自底向上
申请辅助空间arr来存放长度为n的分段乘积的max值,我们知道当绳子的长度小于4的时候,绳子的分段乘积max值是小于绳子长度本身的,所以我们在一开始的arr里面,当绳子长度小于4的时候我们存放绳子本身的长度。
我们有递归公式:f(n)=max(f(i)*f(n-i),) i为剪的某一段的长度。我们一开始从n=4,n=5,n=6一直计算到n=n;

  1. public class Solution {
  2. public int cutRope(int target) {
  3. if(target<2)
  4. return 0;
  5. if(target==2)
  6. return 1;
  7. if(target==3)
  8. return 2;
  9. int[] arr = new int[target+1];
  10. int max = -1;
  11. arr[0] = 0;
  12. arr[1] = 1;
  13. arr[2] = 2;
  14. arr[3] = 3;
  15. for(int i=4;i<=target;i++) {
  16. for(int j=1;j<=i/2;j++) {
  17. int val = arr[j]*arr[i-j];
  18. max = max>val?max:val;
  19. arr[i] = max;
  20. }
  21. }
  22. max = arr[target];
  23. return max;
  24. }
  25. }