题目描述:
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
示例 1:
输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
偷窃到的最高金额 = 1 + 3 = 4 。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/house-robber
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
贴代码:
class Solution {
public:
int rob(vector<int>& nums) {
//非简单的奇偶
//dp算法,当前位置能偷到的最大值,是由前两位及前三位中的最大值加上自己得到,
//如何降空间复杂度为o(1)?
if(nums.size()==0) return 0;
else if(nums.size()==1) return nums[0];
vector<int> maxt={nums[0],nums[1]};
int i;
for(i=2;i<nums.size();i++){
if(i==2) maxt.push_back(nums[0]+nums[2]);
else maxt.push_back(max(maxt[i-3],maxt[i-2])+nums[i]);
}
return max(maxt[i-1],maxt[i-2]);
}
};
标注:非常简单的DP算法,但是如何降空间复杂度为O(1)让我想了一段时间。细节方面处理起来总是不舒服,最终自己写的还是只用了比较笨拙的创建新数组。
先贴答案O(1)空间复杂度的代码。
class Solution {
public:
int rob(vector<int>& nums) {
if (nums.empty()) {
return 0;
}
int size = nums.size();
if (size == 1) {
return nums[0];
}
int first = nums[0], second = max(nums[0], nums[1]);
for (int i = 2; i < size; i++) {
int temp = second;
second = max(first + nums[i], second);
first = temp;
}
return second;
}
};
/*作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/house-robber/solution/da-jia-jie-she-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。*/
标注2:之前也考虑过滚动的方法,拿个特殊测试集考虑 {6,1,2,7,3}
first=6,second=6,
i=2,temp=second=6,second=max(2+6, 6)=8,first=temp=6,一轮循环;
i=3,temp=second=8,second=max(6+7, 8)=13, first=temp=8,二轮循环;
最后一轮不多说,最终返回13没问题。
让我困扰的是,second的赋值方法给了一种会受数组上一位元素影响的印象,而邻位偷窃是违反规则的,所以自己写时总没能想通。如果把second理解成,当前位置能偷的最大值,要么是当前位与前两位之和,要么是上一位;每轮循环后first指向前两位,second指向前一位,这样就能顺利滚动。
就我自己而言,在处理边界问题时总处理不好。大于还是大于等于,在这题是第三位和第四位如何递归下去,如何更新滚动数组。这些都是需要继续积累经验的。尽量把逻辑理得更清晰吧。