总结成一句话就是:走到一间屋要考虑偷还是不偷?
首先考虑最简单的情况。如果只有一间房屋,则偷窃该房屋,可以偷窃到最高总金额。如果只有两间房屋,则由于两间房屋相邻,不能同时偷窃,只能偷窃其中的一间房屋,因此选择其中金额较高的房屋进行偷窃,可以偷窃到最高总金额。
如果房屋数量大于两间,应该如何计算能够偷窃到的最高总金额呢?对于第 k~(k>2) 间房屋,有两个选项:
1.偷窃第 k 间房屋,那么就不能偷窃第 k-1 间房屋,偷窃总金额为前 k-2 间房屋的最高总金额与第 k 间房屋的金额之和。
2. 不偷窃第 k间房屋,偷窃总金额为前 k-1间房屋的最高总金额。
在两个选项中选择偷窃总金额较大的选项,该选项对应的偷窃总金额即为前 k 间房屋能偷窃到的最高总金额。
用 dp[i] 表示前 i间房屋能偷窃到的最高总金额,那么就有如下的状态转移方程:
dp[i]=max(dp[i−2]+nums[i],dp[i−1])
class Solution {
public:
int rob(vector<int>& nums) {
if(!nums.size())return 0;
if(nums.size()==1)return nums[0];
vector<int> dp(nums.size());
dp[0]=nums[0];
dp[1]=max(nums[1],nums[0]);
for(int i=2;i<nums.size();i++){
dp[i]=max(dp[i-2]+nums[i],dp[i-1]);
}
return dp[nums.size()-1];
}
};
如果此题增加难度:
这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。
此时就要考虑第一间屋打不打劫的问题:
class Solution {
private:
vector<int> dp;
public:
int rob(vector<int>& nums) {
if(!nums.size())return 0;
if(nums.size()==1)return nums[0];
if(nums.size()==2)return max(nums[0],nums[1]);
dp.resize(nums.size());
int res=0;
res=max(robwho(nums,0,nums.size()-2),robwho(nums,1,nums.size()-1));
return res;
}
int robwho(vector<int>& nums,int n,int m){
dp[n]=nums[n];
dp[n+1]=max(nums[n],nums[n+1]);
for(int i=n+2;i<=m;i++){
dp[i]=max(dp[(i-2)]+nums[i],dp[i-1]);
}
return dp[m];
}
};