DAY33

87 阅读3分钟

第九章 动态规划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… 你提供的分析步骤很详细,涵盖了如何通过动态规划解决整数拆分问题的每个环节。动规五部曲是分析动态规划问题的经典方式,以下是你的分析摘要:

动规五部曲:

  1. 确定 dp 数组含义

    • dp[i] 表示将整数 i 拆分成两个或多个正整数后,这些数乘积的最大值。
  2. 递推公式

    • 递推公式的推导基于两种情况:一种是直接拆分为两个数相乘,另一种是将 i-j 再次拆分。递推公式为: [ dp[i] = \max(dp[i], \max((i - j) \times j, dp[i - j] \times j)) ]
    • 这公式意味着,dp[i] 是从拆分 i 的所有可能性中找到乘积的最大值。
  3. dp 数组的初始化

    • dp[2] = 1,因为整数 2 只能拆分为 1 和 1,乘积为 1。
    • dp[0]dp[1] 没有意义,所以不需要初始化。
  4. 遍历顺序

    • 因为 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));
          }
      }
      
  5. 优化

    • 由于拆分的最优策略总是将 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] 的值通过两种方式求最大值:
    1. j * (i - j):表示直接拆分为两个数相乘。
    2. j * dp[i - j]:表示将 i - j 再次拆分后的最大值。
  • 遍历到 i / 2:因为对称性,遍历到 i / 2 就足够,不需要遍历到 i

优化的思路:

  • 在考虑拆分的时候,尽量将数字拆分为接近相等的部分,这样可以保证乘积最大,这也是为什么在遍历时只需要考虑到 i / 2

通过这五步,动态规划的整体解法思路就清晰了,优化后的解法也可以保证高效性。

96.  .不同的二叉搜索树 (可跳过)

本题思路并不容易想,一刷建议可以跳过。 如果学有余力,可以看视频理解一波。

programmercarl.com/0096.%E4%B8…

视频讲解:www.bilibili.com/video/BV1eK…