第九章 动态规划part02
今天开始逐渐有 dp的感觉了,前 两题 不同路径,可以好好研究一下,适合进阶
详细布置
62.不同路径
本题大家掌握动态规划的方法就可以。 数论方法 有点非主流,很难想到。
programmercarl.com/0062.%E4%B8…
视频讲解:www.bilibili.com/video/BV1ve…
63. 不同路径 II
programmercarl.com/0063.%E4%B8…
视频讲解:www.bilibili.com/video/BV1Ld…
343. 整数拆分 (可跳过)
本题思路并不容易想,一刷建议可以跳过。如果学有余力,可以看视频理解一波。
programmercarl.com/0343.%E6%95…
视频讲解:www.bilibili.com/video/BV1Mg… 你提供的分析步骤很详细,涵盖了如何通过动态规划解决整数拆分问题的每个环节。动规五部曲是分析动态规划问题的经典方式,以下是你的分析摘要:
动规五部曲:
-
确定 dp 数组含义:
dp[i]表示将整数i拆分成两个或多个正整数后,这些数乘积的最大值。
-
递推公式:
- 递推公式的推导基于两种情况:一种是直接拆分为两个数相乘,另一种是将
i-j再次拆分。递推公式为: [ dp[i] = \max(dp[i], \max((i - j) \times j, dp[i - j] \times j)) ] - 这公式意味着,
dp[i]是从拆分i的所有可能性中找到乘积的最大值。
- 递推公式的推导基于两种情况:一种是直接拆分为两个数相乘,另一种是将
-
dp 数组的初始化:
dp[2] = 1,因为整数 2 只能拆分为 1 和 1,乘积为 1。dp[0]和dp[1]没有意义,所以不需要初始化。
-
遍历顺序:
- 因为
dp[i]是依赖于dp[i-j]的值,所以需要从小到大遍历i。即:for (int i = 3; i <= n; i++) { for (int j = 1; j <= i / 2; j++) { dp[i] = max(dp[i], max((i - j) * j, dp[i - j] * j)); } }
- 因为
-
优化:
- 由于拆分的最优策略总是将
i尽量拆分为接近相等的数,因此只需枚举到i / 2,这样可以减少计算量。
- 由于拆分的最优策略总是将
具体的代码实现:
以下是完整的动态规划代码实现整数拆分问题:
/**
* @param {number} n
* @return {number}
*/
var integerBreak = function(n) {
if (n === 2) return 1; // 特殊情况直接返回
let dp = new Array(n + 1).fill(0);
dp[2] = 1;
for (let i = 3; i <= n; i++) {
for (let j = 1; j <= Math.floor(i / 2); j++) {
dp[i] = Math.max(dp[i], Math.max((i - j) * j, dp[i - j] * j));
}
}
return dp[n];
};
关键点解释:
- 递推公式:
dp[i]的值通过两种方式求最大值:j * (i - j):表示直接拆分为两个数相乘。j * dp[i - j]:表示将i - j再次拆分后的最大值。
- 遍历到
i / 2:因为对称性,遍历到i / 2就足够,不需要遍历到i。
优化的思路:
- 在考虑拆分的时候,尽量将数字拆分为接近相等的部分,这样可以保证乘积最大,这也是为什么在遍历时只需要考虑到
i / 2。
通过这五步,动态规划的整体解法思路就清晰了,优化后的解法也可以保证高效性。
96. .不同的二叉搜索树 (可跳过)
本题思路并不容易想,一刷建议可以跳过。 如果学有余力,可以看视频理解一波。