1. 打家劫舍问题解析
这道经典的动态规划问题来自力扣Hot100题库,题目描述很简单:你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
1.1 问题建模
首先我们需要将这个问题转化为数学模型。给定一个非负整数数组nums,其中nums[i]表示第i个房屋存放的金额,我们需要找到一个子序列,满足:
- 子序列中不能包含相邻的元素
- 在所有满足条件的子序列中,元素和最大的那个
例如对于输入[1,2,3,1],最优解是偷第1和第3个房屋,总和为1+3=4。
1.2 暴力解法分析
最直观的解法是枚举所有可能的子序列,然后找出符合条件的最大和。对于一个长度为n的数组,这样的子序列有2^n种可能(每个房屋要么偷要么不偷),时间复杂度为O(2^n),这在n较大时显然不可行。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 动态规划解法详解
2.1 状态定义
动态规划的核心在于找到合适的状态定义和状态转移方程。对于这个问题,我们可以定义:
dp[i]:考虑前i个房屋(从0开始编号)时能偷窃到的最大金额
这里需要注意"考虑前i个房屋"并不一定表示一定要偷第i个房屋,只是表示我们当前考虑的范围。
2.2 状态转移方程
对于第i个房屋,我们有两种选择:
- 不偷第i个房屋:此时最大金额等于考虑前i-1个房屋时的最大金额,即dp[i-1]
- 偷第i个房屋:那么第i-1个房屋就不能偷,最大金额等于考虑前i-2个房屋时的最大金额加上当前房屋的金额,即dp[i-2] + nums[i]
我们需要在这两种选择中取最大值,因此状态转移方程为:
dp[i] = max(dp[i-1], dp[i-2] + nums[i])
2.3 边界条件
初始状态需要考虑:
- dp[0] = nums[0] (只有一个房屋时只能偷它)
- dp[1] = max(nums[0], nums[1]) (两个房屋时偷金额较大的那个)
2.4 空间优化
观察状态转移方程可以发现,dp[i]只依赖于dp[i-1]和dp[i-2],因此我们不需要保存整个dp数组,只需要保存前两个状态即可。这就是为什么原始代码中使用pr
