题目描述
解题思路
DP
- dp数组表示的含义
dp[i]:分拆数字i,可以得到的最大乘积为dp[i]。
- 确定递推公式
将数分解为两个数相乘,即为(i - j) j ,如果分解为两个以上的数相乘那么就是dp[i - j] j。
j是从1开始遍历,拆分j的情况,在遍历j的过程中其实都计算过了。那么从1遍历j,比较(i - j) j和dp[i - j] j 取最大的。递推公式:dp[i] = max(dp[i], max((i - j) j, dp[i - j] j));
- 初始化
dp[0]和dp[1]是没有意义的,所以初始化dp[2]为1
- 确定遍历顺序
确定遍历顺序,先来看看递归公式:dp[i] = max(dp[i], max((i - j) j, dp[i - j] j));
dp[i] 是依靠 dp[i - j]的状态,所以遍历i一定是从前向后遍历,先有dp[i - j]再有dp[i]。
- 举例推导dp数组
举例当n为10 的时候,dp数组里的数值,如下:
/**
* 动态规划
*
* @param n
* @return
*/
public int integerBreak(int n) {
// dp[i]表示整数为i,被拆分之后相乘的最大值
int[] dp = new int[n + 1];
// 初始化
// dp[0] 和 dp[1] 0和1无法被拆分,所以不需要初始化
// 应该初始化dp[2]
dp[2] = 1;
// 遍历是从前向后,现有dp[i - j] 才会有 dp[i]
for (int i = 3; i <= n; i++) { // 遍历i,构造dp数组
for (int j = 1; j < i - 1; j++) { // 遍历j,找i中拆分出来的数
// 递推公式
// j * (i - j)表示两个数相乘
// dp[i - j] * j表示两个或者两个数以上相乘
// 与dp[i]比较的意思是,遍历j的时候找出最大相乘的数,赋值给dp[i]
dp[i] = Math.max(dp[i], Math.max(dp[i - j] * j, j * (i - j)));
}
}
return dp[n];
}
贪心
本题也可以用贪心,每次拆成n个3,如果剩下是4,则保留4,然后相乘,但是这个结论需要数学证明其合理性!
public int integerBreak(int n) {
if (n == 2) return 1;
if (n == 3) return 2;
if (n == 4) return 4;
int result = 1;
while (n > 4) {
result *= 3;
n -= 3;
}
result *= n;
return result;
}
类似题型
剑指 Offer 14- I. 剪绳子
题目描述
解题思路
和上面一题一个做法
// 动态规划
public int cuttingRope(int n) {
int[] dp = new int[n + 1];
dp[1] = 1;
dp[2] = 1;
for (int i = 3; i <= n; i++) {
for (int j = 1; j < i; j++) {
dp[i] = Math.max(dp[i], Math.max((i - j) * j, dp[i - j] * j));
}
}
return dp[n];
}