题目
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例
示例 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 。
分析
动态规划
设 dp[i]
表示偷窃前 i
间房屋所能获得的最高金额。对于第 i
间房屋,有两种选择:
- 不偷窃第
i
间房屋,那么dp[i] = dp[i - 1]
,也就是偷窃前i - 1
间房屋的最高金额。 - 偷窃第
i
间房屋,那么就不能偷窃第i - 1
间房屋,此时dp[i] = dp[i - 2] + nums[i]
,即偷窃前i - 2
间房屋的最高金额加上第i
间房屋的金额。
综合这两种情况,状态转移方程为:dp[i] = max(dp[i - 1], dp[i - 2] + nums[i])
。
可以发现,计算 dp[i]
时只需要用到 dp[i - 1]
和 dp[i - 2]
,因此可以将空间复杂度优化到 O(1)。
时间复杂度:O(),
是数组的长度
空间复杂度:O(1)
class Solution {
public:
int rob(std::vector<int>& nums) {
int n = nums.size();
if (n == 0) return 0;
if (n == 1) return nums[0];
int prev2 = nums[0];
int prev1 = std::max(nums[0], nums[1]);
int current;
for (int i = 2; i < n; ++i) {
current = std::max(prev1, prev2 + nums[i]);
prev2 = prev1;
prev1 = current;
}
return prev1;
}
};