Java

题目描述

给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为k[1],...,k[m]。请问k[1]x...xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

解题思路

思路一:贪心

假设k[0]-k[m]中有x个2,y个3,则有:
2x+3y=k
其乘积为:
图片说明
这是一个随y递增的函数,因此要保证最后的乘积最大,则y需要尽可能大,既3的个数要尽可能多
证毕,附代码如下:

public class Solution {
    public int cutRope(int target) {
        int sum = 1;
        if(target < 4){
            return target - 1;
        }
        while(target > 4){
            sum *= 3;
            target -= 3;
        }
        sum *= target;
        return sum;


    }
}

思路二:动态规划

动态规划求解问题的四个特征:
①求一个问题的最优解;
②整体的问题的最优解是依赖于各个子问题的最优解;
③小问题之间还有相互重叠的更小的子问题;
④从上往下分析问题,从下往上求解问题
因此可以从小的绳子的最值开始进行推演。
规律:

  1. 2和3不用拆

  2. target的拆分结果中[任意几段]一定是[这几段对应的和长度]的最优解

  3. 任意一段长度大于3的绳子切割后一定可以得到比原来更优或者至少一样好的解
    代码如下:

    public class Solution {
    public int cutRope(int target) {
     //特殊情况
     if (target<=3) return target-1;
     int[] ret = new int[target+1];
     ret[2] = 2;
     ret[3] = 3;
     for (int i=4; i<=target; i++){
         ret[i] = Math.max(ret[i-2]*2, ret[i-3]*3);
     }
     return ret[target];
    }
    }

    另一种代码形式如下:

    public class Solution {
     public int cutRope(int n) {
        // n<=3的情况,m>1必须要分段,例如:3必须分成1、2;1、1、1 ,n=3最大分段乘积是2,
         if(n==2)
             return 1;
         if(n==3)
             return 2;
         int[] dp = new int[n+1];
         /*
         下面3行是n>=4的情况,跟n<=3不同,4可以分很多段,比如分成1、3,
         这里的3可以不需要再分了,因为3分段最大才2,不分就是3。记录最大的。
          */
         dp[1]=1;
         dp[2]=2;
         dp[3]=3;
    
         for (int i = 4; i <= n; i++) {
             int res=0;//记录最大的
             for (int j = 1; j <=i/2 ; j++) {
                 res=Math.max(res,dp[j]*dp[i-j]);//这里需要是两个dp值的乘积,而不是我之前想的j*dp[i-j]
             }
             dp[i]=res;
         }
         return dp[n];
     }
    }
    //这个多了循环

    参考博客

    https://blog.nowcoder.net/n/636e3381b4524cac846cf5f64930496a
    https://blog.nowcoder.net/sophia1995
    https://blog.nowcoder.net/yuyanging