213. House Robber II
思路:
最近发现动规很多都是从后面开始想,这题就是先考虑,第一个房子不偷和最后一个房子不偷的情况。
第一个房子不偷,就是nums[1:],最大金额是P2,最后一个房子不偷,就是nums[:n-1],最大金额是P1,那么取max(P2,P1)
对于第n个房子,如果偷了第n-1个房子,那么第n个就不偷,那么就会偷第n+1个房子;如果不偷第n-1个房子,那么就偷第n个,不会偷第n+1个。
那么转移方程为 dp[n+1] = max(dp[n-1]+nums[i+1],dp[n])。
第n间可能没有被偷,但仍然把dp[n]取上次最大值,dp[n]=dp[n-1],因为不需要判断哪些房子被偷只要记录总的金额,那么就可以将两种情况合并成一种考虑并不会影响结果。可以用例子:2,7,9,3,1退一下,加1的那步就体现出来了。
又因为最后房子和第一个房子算相邻,我们需要遍历两次nums,第一次是偷第一个房子,第二次是不偷第一个房子,从第二个房子开始。
但我们可以不用dp数组,而使用一个变量临时存,就能获得常数空间复杂度。如下
代码:
class Solution {
public:
int dp(vector<int>& nums,int start,int end){
int first=nums[start],second=max(nums[start+1],nums[start]);
for(int i=start+2;i<=end;++i){
int temp=second;
second=max(first+nums[i],second); //转移方程
first=temp;
}
return second;
}
int rob(vector<int>& nums) {
int n=nums.size();
if(n==1) return nums[0];
if(n==2) return max(nums[0],nums[1]);
return max(dp(nums,0,n-2),dp(nums,1,n-1)); //偷第一个房子和不偷第一个房子的两个情况
}
};
时间复杂度为O(n),空间复杂度为O(1)