Leetcode——剪绳子(最大乘积)

1. 剪绳子1

在这里插入图片描述

(1)动态规划

  • 我们想要求长度为n的绳子剪掉后的最大乘积,可以从前面比n小的绳子转移而来
  • 用一个dp数组记录从0到n长度的绳子剪掉后的最大乘积,也就是dp[i]表示长度为i的绳子剪成m段后的最大乘积,初始化dp[2] = 1
  • 我们先把绳子剪掉第一段(长度为j),如果只剪掉长度为1,对最后的乘积无任何增益,所以从长度为2开始剪
  • 当 i≥2 时,假设对正整数 i 拆分出的第一个正整数是 j(1≤j<i),则有以下两种方案:
    将 i 拆分成 j 和 i−j 的和,且 i−j 不再拆分成多个正整数,此时的乘积是 j×(i−j);
    将 i 拆分成 j 和 i−j 的和,且 i−j 继续拆分成多个正整数,此时的乘积是 j×dp[i−j]。
  • 第一段长度j可以取的区间为[2,i),对所有j不同的情况取最大值,因此最终dp[i]的转移方程为
    dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]))
  • 最后返回dp[n]即可
class Solution {
    public int cuttingRope(int n) {
        int[] dp = new int[n + 1];
        dp[2] = 1;
        for(int i = 3; i < n + 1; i++){
            for(int j = 2; j < i; j++){
               //为什么可以固定一个j呢,因为j在遍历中都能被取到
                dp[i] = Math.max(dp[i], Math.max(j * (i - j), j * dp[i - j]));
            }
        }
        return dp[n];
    }
}

如果看不懂的话,来个最容易懂的:

  • 固定划分点,继续看子划分区间能不能继续划分
class Solution {
    public int cuttingRope(int n) {
        int[] dp = new int[n + 1];

         //i表示绳子长度,i最长可以为n
        for (int i = 2; i < n + 1; i++) {   
            for (int j = 1; j < i; j++) {
                //都不能分了
                int a = j * (i - j);

                // j不能分,i-j能分
                int b = j * dp[i-j];

                //i-j不能分,j能分
                int c = dp[j] * (i - j);

                //i-j能分,j也能分
                int d = dp[j] * dp[i-j];

                //dp[i]记录当前长度绳子剪过之后的最大乘积,选择该段要不要剪
                int e = dp[i];

                //求最大值
                dp[i] = Math.max(Math.max(Math.max(a,b),Math.max(c,d)),e);
            }
        }
        return dp[n];
    }
}

(2)贪心

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

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

2. 剪绳子 2 (n很大时)

class Solution {
    public int cuttingRope(int n) {
        if(n == 2)  
        	return 1;
        if(n == 3)  
        	return 2;
        long a = 1;
        long mod = 1000000007;
        while(n > 4){
            n = n - 3;
            a = (a * 3) % mod;
        }
        long ans = a * n % mod;
        return (int)ans;
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yawn__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值