1. 动态规划经典问题:打家劫舍系列解析
今天我们来拆解算法训练中经典的"打家劫舍"问题系列,包含三个不同变种:基础版(198题)、环形版(213题)和二叉树版(337题)。这三个问题层层递进,是动态规划(DP)应用的绝佳案例。作为算法工程师,我经常在面试中考察这类问题,因为它能很好地检验候选人对DP思想的理解深度。
打家劫舍问题的核心在于:在不触发警报的情况下,如何选择最优的房屋组合使得总收益最大化。警报触发的条件是相邻房屋在同一晚被打劫。三个变种分别对应不同的房屋排列方式——线性排列、环形排列和二叉树排列。我们将从最简单的线性DP开始,逐步深入到需要结合树形DP的复杂场景。
提示:建议按顺序学习这三个问题,理解DP思想如何从一维扩展到二维,再到树形结构。这是掌握动态规划思维的关键路径。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 基础版:线性排列房屋(198.打家劫舍)
2.1 问题描述与状态定义
给定一个非负整数数组nums,表示沿街排列的房屋中的金额。作为专业劫匪,你需要在不触动警报的情况下(不能连续打劫相邻房屋),计算今晚能盗取的最高金额。
示例:
输入:[2,7,9,3,1]
输出:12
解释:选择第1、3、5号房屋(2+9+1=12)
状态定义是DP问题的核心。对于这类最值问题,我们通常定义dp[i]为考虑前i个房屋时能获得的最大金额。关键在于理解"考虑"的含义——它不一定包含第i个房屋,只是表示决策进行到了第i个位置。
2.2 状态转移方程推导
对于第i个房屋,我们有两个选择:
- 打劫它:那么不能打劫i-1,最大金额为dp[i-2] + nums[i]
- 不打劫它:最大金额保持为dp[i-1]
因此状态转移方程为:
dp[i] = max(dp[i-1], dp[i-2] + nums[i])
边界条件:
dp[0] = nums[0] (只有一间房时必选)
dp[1] = max(nums[0], nums[1]) (两间房选金额大的)
2.3 空间优化与实现
基础实现需要O(n)空间,但观察发现dp[i]只依赖前两个状态,因此可以优化到O(1)空间:
python复制def rob(nums):
if not nums: return 0
prev1 = prev2 = 0
fo
