打家劫舍问题
class Solution {
public:
int rob(vector<int>& nums) {
vector<int>dp(nums.size(),0);
int M=nums.size();
if(M<=0) return 0;
if(M==1) return nums[0];
if(M==2) return max(nums[0],nums[1]);
dp[0]=nums[0];
dp[1]=max(nums[0],nums[1]);
int res=INT_MIN;
for(int i=2;i<nums.size();i++)
{
dp[i]=max((dp[i-2]+nums[i]),dp[i-1]);
cout<<dp[i];
// res=max(res,dp[i]);
}
return dp[M-1];
}
};
通过奇数偶数来判断 来源
还有一种解法,核心思想还是用 DP,分别维护两个变量 robEven 和 robOdd,顾名思义,robEven 就是要抢偶数位置的房子,robOdd 就是要抢奇数位置的房子。所以在遍历房子数组时,如果是偶数位置,那么 robEven 就要加上当前数字,然后和 robOdd 比较,取较大的来更新 robEven。这里就看出来了,robEven 组成的值并不是只由偶数位置的数字,只是当前要抢偶数位置而已。同理,当奇数位置时,robOdd 加上当前数字和 robEven 比较,取较大值来更新 robOdd,这种按奇偶分别来更新的方法,可以保证组成最大和的数字不相邻,最后别忘了在 robEven 和 robOdd 种取较大值返回,代码如下
class Solution {
public:
int rob(vector<int>& nums) {
int robEven=0;
int robOdd=0;
int n=nums.size();
for(int i=0;i<n;i++)
{
if(i%2==0){
robEven=max(robEven+nums[i],robOdd);
}else{
robOdd=max(robOdd+nums[i],robEven);
}
}
return max(robEven,robOdd);
}
};
压缩空间
我们注意到
dp[i] 只和dp[i-1] dp[i-2] 这两个状态有关所以我们可以 用两个变量来保存有关的值 类似滚动数组
int rob(vector<int>& nums) {
int prev = 0;
int curr = 0;
// 每次循环,计算“偷到当前房子为止的最大金额”
for (int i : nums) {
// 循环开始时,curr 表示 dp[k-1],prev 表示 dp[k-2]
// dp[k] = max{ dp[k-1], dp[k-2] + i }
int temp = max(curr, prev + i);
prev = curr;
curr = temp;
// 循环结束时,curr 表示 dp[k],prev 表示 dp[k-1]
}
return curr;
}