剑指 Offer 14- I. 剪绳子——动态规划and贪心

剪绳子

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

示例 1:
输入: 2
输出: 1
解释: 2 = 1 + 1, 1 × 1 = 1

示例 2:
输入: 10
输出: 36
解释: 10 = 3 + 3 + 4, 3 × 3 × 4 = 36

来源:力扣(LeetCode)
链接:点击跳转https://leetcode-cn.com/problems/jian-sheng-zi-lcof


动态规划

解题思路:

  1. 我们想要求长度为n的绳子剪掉后的最大乘积,可以从前面比n小的绳子转移而来
  2. 用一个dp数组记录从0到n长度的绳子剪掉后的最大乘积,也就是dp[i]表示长度为i的绳子剪成m段后的最大乘积,初始化dp[2] = 1
  3. 我们先把绳子剪掉第一段(长度为j),如果只剪掉长度为1,对最后的乘积无任何增益,所以从长度为2开始剪
  4. 剪了第一段后,剩下(i - j)长度可以剪也可以不剪。如果不剪的话长度乘积即为j * (i - j);如果剪的话长度乘积即为j * dp[i - j]。取两者最大值max(j * (i - j), j * dp[i - j])
  5. 第一段长度j可以取的区间为[2,i),对所有j不同的情况取最大值,因此最终dp[i]的转移方程为dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]))
  6. 最后返回dp[n]即可
class Solution {
    
    
    //动态规划
    public int cuttingRope(int n) {
    
    
        int[] dp = new int[n+1];   //从长度为0到长度为n,一共有n+1个长度
        int i;  //i代表长度为i的线
        int j;  //j代表剪掉线的长度
        dp[2] = 1;  //当线长度为2的时候,最大的乘积肯定是1,d[1],d[0]为创建数组的默认值0
        //i从3开始,因为小于3的长度的最大乘积很明确,一直遍历到最大的长度,得到dp[i]长度为i的绳子剪成m段后的最大乘积
        for(i = 3; i < dp.length; i++) {
    
    
            //剪掉的长度为j,一直遍历到该绳子的最大长度
            for(j = 2; j < i; j++) {
    
    
                int tmp = Math.max(j*(i-j),j*dp[i-j]);  //剪掉j后的长度为i-j,所以乘积就为j*(i-j)
                //如果剪掉j后再要继续剪,那么就相当于再从i-j中得出最大乘积,i-j绳的最大乘积就为之前算出来的dp[i-j]
                //所以最后直接判断 只剪断j的乘积 和 剪断j后继续再剪的乘积 的最大值就可以
                dp[i] = Math.max(dp[i],tmp);    //比较前一个剪断j后的最大乘积 和 现在剪断j后的最大乘积,因为j是一直变化的
            }
        }
        //最后只用返回题目需要长度为n的绳子 的最大乘积
        return dp[n];
    }
}

贪心算法

核心思路是:尽可能把绳子分成长度为3的小段,这样乘积最大

步骤如下:

  1. 如果 n == 2,返回1,如果 n == 3,返回2,两个可以合并成n小于4的时候返回n - 1
  2. 如果 n == 4,返回4
  3. 如果 n > 4,分成尽可能多的长度为3的小段,每次循环长度n减去3,乘积res乘以3;最后返回时乘以小于等于4的最后一小段
  4. 以上2和3可以合并
class Solution {
    
    
    public int cuttingRope(int n) {
    
    
        if(n < 4){
    
    
            return n - 1;
        }
        int res = 1;
        while(n > 4){
    
    
            res *= 3;
            n -= 3;
        }
        return res * n;
    }
}

猜你喜欢

转载自blog.csdn.net/starry1441/article/details/115009014