【算法】动态规划经典题之打家劫舍

82 阅读2分钟

198. 打家劫舍

题目描述

image.png

打家劫舍思路

在这个问题中,假设只有一房屋,则偷窃该房屋,如果有两间房屋,由于不能偷相邻的房屋,所以返回两间房屋中最大的金额。 如果房屋数量大于两间, 那么如何计算呢,假设我要偷第 4 间房屋, 有两种偷法 , 是不是只能偷第1、2 或者 第2、4间, 比比这两种偷法,谁的总金额最大

那么对于 k 间房间(k>2), 有个选项:

  • 如果偷 k 间房间的话,那么金额为 k-2 间房屋的最高金额之和与第 k 间房屋的金额之和
  • 如果不偷 k 间房间的话,那么金额为 k-1 房屋的最高金额之和
  • 看看这两种哪个比较大,哪个大就是最终结果 用 dp[i] 来表示第 i 间房间能够偷窃的最高总金额,那么

状态转移方程

dp[i] = max(dp[i-2] + num[i], dp[i-1])

边界条件为

dp[0]=nums[0]   只有一间房屋,则偷窃该房屋
dp[1]=max(nums[0],nums[1]) 只有两间房屋,选择其中金额较高的房屋进行偷窃

代码示例

空间复杂度 O(n) 解法

function rob(nums: number[]): number {
  let n = nums.length;
  if (n == 1) return nums[0];
  let dp = new Array(n);
  dp[0] = nums[0];
  dp[1] = Math.max(nums[0], nums[1]);
  for (let i = 2; i < n; i++) {
      dp[i] = Math.max(dp[i - 2] + nums[i], dp[i - 1]);
  }
  return dp[n - 1]
};
  • 时间复杂度: O(n) , n 是数组的长度
  • 空间复杂度: O(n), n 是数组的长度

空间复杂度 O(1) 解法,使用滚动数组

function rob(nums: number[]): number {
    let n = nums.length;
    if (n == 1) return nums[0];
    let first = nums[0], second = nums[1];
    let temp = 0
    for (let i = 2; i < n; i++) {
        temp = second;
        second = Math.max(first + nums[i], second);
        first = temp;
    }
    return second
};
  • 时间复杂度: O(n) , n 是数组的长度
  • 空间复杂度: O(1), 仅仅使用了常量作为临时变量