题目
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 1:
输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。偷窃到的最高金额 = 1 + 3 = 4 。
来源:力扣(LeetCode)
思路
相当于在一个数组中取出一个或多个不相邻数,使其和最大;
一般地,对于这类求极值的问题首先考虑动态规划来解。
维护一个一维数组 dp,其中 dp[ i ] 表示 [0, i] 区间可以抢夺的最大值;
对当前的 i 来说,有抢和不抢两个选择,不抢即为 dp[i-1](即就是去掉 nums[i] 只抢 [0, i-1] 区间最大值),抢即为 dp[i-2] + nums[i](即就是去掉 nums[i-1]);
举例说明:比如说 nums为{4, 3,2, 6},来看 dp 数组应该是什么模样?
首先 dp[0]=4 没啥疑问,再看 dp[1] 是多少呢?由于4比3大,所以抢第一个房子的4,当前房子的3不抢,则dp[1]=4;
再来看 dp[2],由于不能抢相邻的房子,所以可以用上上一个的 dp 值加上当前的房间值,去和当前房间的前面一个 dp 值作比较,取两个较大者为当前 dp 值;
这样可以得到 dp[i] = max(num[i] + dp[i - 2], dp[i - 1]), 其中 dp[0] 即为 num[0],dp[1] 为 max(num[0], num[1])。
C++代码
class Solution {
public:
int rob(vector<int>& nums)
{
if (nums.size() <= 1)
{
return nums.empty() ? 0 : nums[0];
}
vector<int> dp = {nums[0], max(nums[0], nums[1])};
for (int i = 2; i < nums.size(); ++i)
{
dp.push_back(max(nums[i] + dp[i - 2], dp[i - 1]));
}
return dp.back();
}
};