给你一根长度为 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
提示:
一、动态规划
首先使用动态规划解决问题,最重要的就是理解dp数组的含义。 此处的dp[i] 表示长度为i的绳子剪成m段后的最大乘积。初始化dp[2] = 1 表示如果一个绳子长度为2必然只能分成两段长度为1的绳子,两者的乘积为1。
j * (i - j)
。如果剪得到的长度为j * dp[i - j]
两者取最大值dp[i] = max(dp[i], max(j * (i - j), j * dp[i - j]))
class Solution {
public int cuttingRope(int n) {
// dp[i]表示长度为i的绳子被剪成m段,每段乘机的最大值
int[] dp = new int[n+1];
// 因为m>1,所以dp[2] = 1而不是2
dp[2] = 1;
// i表示绳子长度
for (int i=3;i<=n;++i){
// i-j >= 2。j代表第一次剪掉的长度,剪掉1没用,所以从2开始,剩余的长度i-j怎么减直接取dp[i-j]
for (int j=1;j<=i-2;++j){
// 这里因为m>1,所以dp[2] = 1而不是2,dp[3]不能是dp[2] * 1,这样答案是1,错误.
// 因此下面要添加Math.max(dp[i-j], i-j)。
dp[i] = Math.max(Math.max(dp[i-j], i-j) * j, dp[i]);
}
}
return dp[n];
}
}
二、贪心算法
这个做题思路直接引用K神吧,直接给跪了。
算法流程:
class Solution {
public int cuttingRope(int n) {
if(n <= 3) return n - 1;
int a = n / 3, b = n % 3;
if(b == 0) return (int)Math.pow(3, a);
if(b == 1) return (int)Math.pow(3, a - 1) * 4;
return (int)Math.pow(3, a) * 2;
}
}
其实K神还有更详细的求导过程和推论过程,建议点参考链接详细再看看。
原文:https://www.cnblogs.com/RainsX/p/15242117.html