# [动态规划] 打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。

TIP

示例1:

输入: [1, 2, 3, 1]

输出: 4

解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)   偷窃到的最高金额 = 1 + 3 = 4

示例2:

输入: [2, 7, 9, 3, 1]

输出: 12

解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)   偷窃到的最高金额 = 2 + 9 + 1 = 12

# 思路

本质上是解决:对于第i个房子,抢 or 不抢

每个元素都是同样的判断:抢 or 不抢。

  • 如果抢,那之后需要i + 2
  • 如果不抢,那之后需要i + 1

最终,返回dp数组中最后一个元素即可。

# 状态数组

  • 如果抢,则dp[i]表示:第(i - 2)个元素之前的最大价值 + 第(i - 2)个元素的价值
  • 如果不抢,则dp[i]表示:第(i - 1)个元素之前的最大价值

最终决定 抢 or 不抢,是根据哪种价值最大。

之所以要给状态数组设置多2个长度,是因为 需提前判断前面两个房子的抢劫情况

# 状态转移方程

dp[0] = 0 // 为了方便计算,给状态数组设置多2个长度,且值为0
dp[1] = 0

dp[i] = Math.max(dp[i - 2], nums[i - 2], dp[i - 1])
1
2
3
4

# 代码实现

/**
 * @param {number[]} nums
 * @return {number}
 */
var rob = function(nums) {
    let dp = [0, 0];

    for (let i = 2; i < nums.length + 2; i++) {
        dp[i] = Math.max(dp[i-2] + nums[i-2], dp[i-1]);
    }
    return dp[nums.length + 1];
};
1
2
3
4
5
6
7
8
9
10
11
12

# 参考链接

更新时间: 4/26/2020, 11:15:47 PM