LeetCode打卡day2——剪绳子

130 阅读1分钟

“Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。”

一、题目描述:

剪绳子 给你一根长度为 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:

输入: n = 5, m = 3 输出: 3

示例 2:

输入: n = 10, m = 17 输出: 2  

限制:

1 <= n <= 10^5

1 <= m <= 10^6

二、思路分析:

  1. 动态规划

可以看出对于长n绳子,可以划分为很多种情况,那能不能得到与之前的长1~n-1绳子划分的最大乘积与当前绳子的关系?

对长为n绳子若取长度x不划分,剩下的n-x按照n-x绳子的最大乘积划分,则n=x+n-x的划分,乘积mul=x*(n-x)的最大乘积,假设dp[n-x]表示绳子n-x的最大乘积,可以得出n与n-x的递推公式:x*dp[n-x]。然后遍历1~n-1绳子取最大值。

但这并不是最终答案,以上我们讨论的都是对剩下的n-x进行划分,还未讨论不进行划分的情况,例如对于绳子4=2+2,最大乘积为2x2而不是2dp【2】,所以还要比较 x(n-x) 故递推公式为 dp[i]=Math.max(dp[i],Math.max(jdp[i-j],j(i-j))),1<=j<=i-1 特别的dp[1]=0

  1. 数学+贪心 可以转换为n=n1​+n2​+...+na,求max(n1​×n2​×...×na​)

image.png

可以得出一个推论,绳子以相等的长度等分为多段 ,得到的乘积最大。 故假设设将绳子按照 x 长度等分为 a 段, image.png

通过对x求导数得到取整数的极大值为3

image.png 得出推论 绳子以长度 33 等分为多段时,乘积最大。

故当n>3时对其求3的倍数a和余数b

  • 当b为0时,绳子以相等的长度3等分为多段,求pow(3,a)
  • 当b为1时,拆借一个3,变为2x2,求pow(3,a-1)*4
  • 当b为2是,pow(3,a)*2

三、AC 代码:

  1. 动态规划
/** 
* @param {number} n 
* @return {number} */ 
var cuttingRope = function(n) { 
    let dp=[0,0] 
    for(let i=2;i<=n;i++){ 
        dp[i]=0 
        for(let j=1;j<i;j++){ 
        dp[i]=Math.max(dp[i],Math.max(j*dp[i-j],j*(i-j))) 
        } 
    } 
    return dp[n] 
};
  1. 贪心+数学
var cuttingRope = function(n) {
    if(n<=3)return n-1
    let a=Math.floor(n/3),b=n%3
    if(b===0)return Math.pow(3,a)
    else if(b===1)return Math.pow(3,a-1)*4
    else return Math.pow(3,a)*2
};

四、总结:

对于动态规划得出递推公式很重要,贪心算法一半都有数学公式证明合理性