读完本文,你可以去力扣拿下如下题目:
198.打家劫舍
213.打家劫舍II
337.打家劫舍III
-----------
有读者私下问我 LeetCode 「打家劫舍」系列问题(英文版叫 House Robber)怎么做,我发现这一系列题目的点赞非常之高,是比较有代表性和技巧性的动态规划题目,今天就来聊聊这道题目。
打家劫舍系列总共有三道,难度设计非常合理,层层递进。第一道是比较标准的动态规划问题,而第二道融入了环形数组的条件,第三道更绝,把动态规划的自底向上和自顶向下解法和二叉树结合起来,我认为很有启发性。如果没做过的朋友,建议学习一下。
下面,我们从第一道开始分析。
House Robber I
![12d6df1562d02eab396ff81c9481e8ef.png](https://img-blog.csdnimg.cn/img_convert/12d6df1562d02eab396ff81c9481e8ef.png)
public int rob(int[] nums);
题目很容易理解,而且动态规划的特征很明显。我们前文「动态规划详解」做过总结,解决动态规划问题就是找「状态」和「选择」,仅此而已。
假想你就是这个专业强盗,从左到右走过这一排房子,在每间房子前都有两种选择:抢或者不抢。
如果你抢了这间房子,那么你肯定不能抢相邻的下一间房子了,只能从下下间房子开始做选择。
如果你不抢这件房子,那么你可以走到下一间房子前,继续做选择。
当你走过了最后一间房子后,你就没得抢了,能抢到的钱显然是 0(base case)。
以上的逻辑很简单吧,其实已经明确了「状态」和「选择」:你面前房子的索引就是状态,抢和不抢就是选择。
![84199adeec091ef429b6f91f75e25783.png](https://img-blog.csdnimg.cn/img_convert/84199adeec091ef429b6f91f75e25783.png)
在两个选择中,每次都选更大的结果,最后得到的就是最多能抢到的 money:
// 主函数
public int rob(int[] nums) {
return dp(nums, 0);
}
// 返回 nums[start..] 能抢到的最大值
private int dp(int[] nums, int start) {
if (start &g