先上笨蛋解法,环形偷的关键在于nums[0]和nums[n-1]不会同时被访问,所以设置两个数组,一个从头偷,一个从尾偷。最终比较从头偷还是从尾偷的数大。
class Solution {
public:
int rob(vector<int>& nums) {
if(nums.empty())
return 0;
if(nums.size()==1)
return nums[0];
int n=nums.size();
vector<int> dp_l(n+1,0);
vector<int> dp_r(n+1,0);
dp_l[1]=nums[0];
dp_r[n-1]=nums[n-1];
for(int i=2;i<n;++i)
{dp_l[i]=max(dp_l[i-1],dp_l[i-2]+nums[i-1]);
dp_r[n-i]=max(dp_r[n-i+1],dp_r[n-i+2]+nums[n-i]);}
return max(dp_l[n-1],dp_r[1]);
}
};
然而看了答案,好吧,也是这种解法,遍历两遍。
中间我还想过比较nums[0]和nums[n-1],谁大就从哪边偷,但是一个很简单的问题就是两个一样大,就没法了。
答案还是有值得学习的地方的。实际上遍历的操作一样,所以可以写一个遍历函数,省去相同的步骤。以及状态空间可以进一步压缩下。
事实证明,我确实是个自作聪明的大傻X.
还专门把数组反转了下。但是实际上只要一个从0-n-2,一个从2-n-1不就可以了。真的是蠢啊。
class Solution {
public:
int myRob(vector<int>& nums,int start,int finish)
{
int res=nums[start],next_1=nums[start],next_2=0;
for(int i=start+1;i<finish;++i)
{
res=max(next_1,next_2+nums[i]);
next_2=next_1;
next_1=res;
}
return res;
}
int rob(vector<int>& nums) {
if(nums.empty())
return 0;
int res,n=nums.size();
res=myRob(nums,0,n-1);
reverse(nums.begin(),nums.end());
return max(res,myRob(nums,0,n-1));
}
};
但是这样的话,就需要加一个size==1的情况
class Solution {
public:
int myRob(vector<int>& nums,int start,int finish)
{
int res=nums[start],next_1=nums[start],next_2=0;
for(int i=start+1;i<finish;++i)
{
res=max(next_1,next_2+nums[i]);
next_2=next_1;
next_1=res;
}
return res;
}
int rob(vector<int>& nums) {
if(nums.empty())
return 0;
if (nums.size()==1)
return nums[0];
return max(myRob(nums,0,nums.size()-1),myRob(nums,1,nums.size()));
}
};