“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
二、思路分析:
- 动态规划
可以看出对于长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
- 数学+贪心 可以转换为n=n1+n2+...+na,求max(n1×n2×...×na)
可以得出一个推论,绳子以相等的长度等分为多段 ,得到的乘积最大。
故假设设将绳子按照 x 长度等分为 a 段,
通过对x求导数得到取整数的极大值为3
得出推论 绳子以长度 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 代码:
- 动态规划
/**
* @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]
};
- 贪心+数学
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
};
四、总结:
对于动态规划得出递推公式很重要,贪心算法一半都有数学公式证明合理性