聪明的小偷系列,和打家劫舍1一样,记录dp[i-1]和i-1之前能偷到的最大总和。因为是个环,所以我们进行两次dp,从0到n-1和1到n,记录下能偷到更大的那个值即可
class Solution {
public:
int rob(vector<int>& nums) {
//第一间房和最后一间房只能偷一个,dp两次,分别dp的是偷第一间房和偷到倒数第二间以及不偷第一间房偷到最后一间
if(nums.size() == 0) return 0;
if(nums.size() == 1) return nums[0];
if(nums.size() == 2) return max(nums[0],nums[1]);
//偷第一间,maxn记录的是除当前房间前一外能偷到的最大值
int maxn = nums[0], pre = nums[1];
int res = max(maxn,pre);
for(int i = 2; i < nums.size()-1; ++i){
res = max(maxn+nums[i],pre);
maxn = max(maxn,pre);
pre = res;
}
int res1 = res;
maxn = nums[1];
pre = nums[2];
for(int i =3; i < nums.size(); ++i){
res = max(maxn+nums[i],pre);
maxn = max(maxn,pre);
pre = res;
}
return max(res1,res);
}
};
pre记录的是偷或者不偷前一间能得到的最大值,maxn是除了前一间能偷到的最大值,因为不一定是前两间,有可能隔着2间。
class Solution {
public:
int rob(vector<int>& nums) {
//紧挨着的,所以第一个和最后一个不能连续偷
//这道题的dp不是普通的记录前两个,而是记录dp[i-1]和不偷nums[i-1]能得到的最大值,因为如果是[1,2,1,1,2]这样的,两个2中间隔了两个也可能得到最大值
if(nums.size() == 1) return nums[0];
//为了防止只有两个数,我们进行第二次dp的时候会越界,所以提前判断
if(nums.size() == 2) return max(nums[0],nums[1]);
int maxn = nums[0], pre = nums[1];
int res1 = max(pre,maxn);
//pre是dp[i-1]
for(int i = 2; i < nums.size()-1; ++i){
res1 = max(maxn+nums[i],pre);
maxn = max(pre,maxn);
pre = res1;//更新dp[i-1]为dp[i]
}
pre = nums[2], maxn = nums[1];
int res2 = max(pre,maxn);
for(int i = 3; i < nums.size(); ++i){
res2 = max(maxn+nums[i],pre);
maxn = max(pre,maxn);
pre = res2;
}
return max(res1,res2);
}
};