198. 打家劫舍

中等 含交互动画

学完这道你应该能: 说清它为什么用「一维 DP」,而不是死记步骤; 合上页面,自己默写出核心代码; 用 30 秒把思路讲清楚。

AI 私教 · 就着本题动画讲
卡住了不用硬扛,按 8 步把这题真正走通。
从读题、试解、找法到手写代码,边问边打勾,适合第一次系统学算法的同学。

题目描述

一排房子各有现金,不能偷相邻两家(会报警),求最多能偷到多少。

nums = [2, 7, 9, 3, 1]
输出 = 12 (偷 2 + 9 + 1)

思路解析

最直接的想法:让每家都「偷 / 不偷」二选一,再扔掉相邻冲突的组合——n 家就有 2 的 n 次方种,组合数指数爆炸。而且「前 i 家最多偷多少」这个小问题,会在不同枚举分支里被反复重算慢就慢在重复子问题

换个角度:dp[i] 记「到第 i 家为止最多偷多少」。到第 i 家只有两条路——不偷就继承 dp[i-1];就只能接不相邻的 dp[i-2] 再加 nums[i]。取大的:dp[i] = max(dp[i-1], dp[i-2] + nums[i])。为什么能记表?每个「前 i 家」只算一次存进 dp,后面直接查,省掉重复递归——这就是重叠子问题

建表:表固定 1 行 5 列,表头是每家的现金。dp[i] 表示「到第 i 家为止最多能偷多少」,咱从左到右一格一格填。

dp[0] = 2 · 地基:只有第 1 家时肯定偷:dp[0] = 2。这是不依赖别人的「地基」格。

dp[1] = max(2, 7):前两家相邻只能选一个:不偷第 2 家就拿 dp[0]=2,偷第 2 家就拿 7。取大的 7,dp[1] = 7。

dp[2] · 偷 9:看第 3 家:偷它(9)就得跳过相邻的第 2 家,接 dp[0]=2,共 11;不偷就继承 dp[1]=7。更赚,dp[2] = 11。这就是核心一步——偷当前要接 dp[i-2],不是 dp[i-1]。

dp[3] · 先试「偷它」:看第 4 家(3):先算「偷」这条路——跳过第 3 家、接 dp[1]=7,加上 3 得 10。先记着这个候选,还要和「不偷」比一比。

dp[3] · 偷它不如不偷:再看「不偷」:直接继承 dp[2]=11。偷它(10)反而不如不偷(11)这一步是负例:偷当前并不总是赚,max 自动选了「不偷、继承 dp[i-1]」。dp[3] = 11

dp[4] · 偷 1:最后一家(1):偷它接 dp[2]=11 共 12,比不偷的 11 多 1。dp[4] = 12。

答案 = 最后一格:表格最后一格 dp[4] = 12 就是答案,正对应偷第 1、3、5 家(2+9+1)。每个值只算了一次。

「选当前 + 跳过相邻」和「不选当前 + 继承上一个」取最优——打家劫舍、删除并获得点数、按摩师都是这个套路。

参考代码(Python)

Python
1def rob(self, nums):
2    if not nums: return 0
3    prev2, prev1 = 0, 0          # dp[i-2], dp[i-1]
4    for x in nums:
5        cur = max(prev1, prev2 + x)   # 不偷 vs 偷
6        prev2, prev1 = prev1, cur     # 滚动前移
7    return prev1

复杂度分析

  • 时间复杂度:O(n) —— 从头到尾扫一遍,每家只算一次
  • 空间复杂度:O(1) —— 只滚动 prev2、prev1 两个变量,不用整张表

套路模板

记住骨架:不选 = 继承 prev1、选 = prev2 + 当前、两者取优、滚动前移。改一下「选的约束」就能套一大类一维 DP。

Python
1# 「每个元素选或不选、选了有约束」都套
2prev2, prev1 = 0, 0
3for x in nums:
4    cur = max(prev1,            # 不选当前
5              prev2 + x)        # 选当前(接更前面的)
6    prev2, prev1 = prev1, cur
7return prev1

易错点

  • 错误写法:偷当前时接 dp[i-1]正确写法:接 dp[i-2](相邻不能同偷,偷第 i 家必须跳过紧挨的第 i-1 家,只能接 dp[i-2])
  • 错误写法:滚动赋值顺序写反正确写法:prev2, prev1 = prev1, cur 一次性更新(先改 prev1 再用它算 prev2,会用到被覆盖的旧值导致结果错)
  • 错误写法:空数组不特判正确写法:先处理 nums 为空返回 0(否则空输入时返回值含义不对)

以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握

下一题 →739. 每日温度 ← 返回题库