# 动态规划

  • 动态规划是算法设计中的一种方法;
  • 他将一个问题分解为相互重叠的子问题,通过反复求解子问题,来解决原来的问题;

动态规划与分而治之区别就在于分解的子问题是不是重叠的,分而治之的子问题是相互独立的,而动态规划分解的子问题的相互重叠的。

# 应用场景

# 斐波那契数列

  • 定义子问题:F(n) = F(n - 1) + F(n - 2);
  • 反复执行:从 2 循环到 n,执行上面的公式;

# 算法题:爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数。

示例 1:

输入: 2
输出: 2
解释: 有两种方法可以爬到楼顶。
1.  1 阶 + 12.  2

链接:https://leetcode-cn.com/problems/climbing-stairs

  • 解题思路:爬到第 n 阶可以在第 n - 1 阶爬 1 个台阶,或者在第 n - 2 阶爬 2 个 台阶。得到公式:F(n) = F(n - 1) + F(n - 2);可以使用动态规划;
  • 解题步骤:定义子问题:F(n) = F(n - 1) + F(n - 2);然后反复执行:从 2 循环到 n,执行前面的公式;

时间复杂度:O(n); 空间复杂度:O(n);

/**
 * @param {number} n
 * @return {number}
 */
var climbStairs = function(n) {
    if(n < 2) { return 1; }
    // 记录第 n 阶需要的方法
    const dp = [1, 1];
    for (let i = 2; i <= n; i += 1) {
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    return dp[n];
};

可以优化空间复杂度为 O(1):

/**
 * @param {number} n
 * @return {number}
 */
var climbStairs = function(n) {
    if(n < 2) { return 1; }
    let dp0 = 1, dp1 = 1;
    for (let i = 2; i <= n; i += 1) {
        [dp0, dp1] = [dp1, dp1 + dp0];
    }
    return dp1;
};

# 算法题:打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

示例 1:

输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4

链接:https://leetcode-cn.com/problems/house-robber

  • 解题思路:f(k) = 从前 k 个房屋中能偷窃到的最大金额;Ak = 第 k 个房屋的钱数。f(k) = max(f(k - 2) + Ak, f(k - 1));使用动态规划;
  • 解题步骤:定义子问题:f(k) = max(f(k - 2) + Ak, f(k - 1))。然后反复执行:从 2 循环到 n,执行公式。

时间复杂度:O(n); 空间复杂度:O(n);

/**
 * @param {number[]} nums
 * @return {number}
 */
var rob = function(nums) {
  let n = nums.length;
  // 如果是空数组直接返回 0
  if (n === 0) {
    return 0;
  }
  const dp = [0, nums[0]];
  for (let i = 2; i <= n; i += 1) {
      dp[i] = Math.max(dp[i - 2] + nums[i - 1], dp[i - 1]);
  }
  return dp[n];
};

优化空间复杂度:O(1);

/**
 * @param {number[]} nums
 * @return {number}
 */
var rob = function(nums) {
  let n = nums.length;
  // 如果是空数组直接返回 0
  if (n === 0) {
    return 0;
  }
  let dp0 = 0, dp1 = nums[0];

  for (let i = 2; i <= n; i += 1) {
      const dp2 = Math.max(dp0 + nums[i - 1], dp1);
      dp0 = dp1;
      dp1 = dp2;
  }
  return dp1;
};

评 论:

更新: 12/14/2020, 5:20:33 PM