You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.
(假设你是一个正计划偷窃一条街道的盗贼,每栋房子都有一个藏有钱的保险柜,唯一能够阻止你偷窃的是相邻房子之间有安保系统连接,只要俩相邻房子在同一晚被闯入就会自动报警)
Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.
(给定一个非负整数的列表来表示每栋房子所含的钱数,求出在不发出警报的情况下所能得到的最多钱)
1.个人分析
可将问题理解为在一个非负整型数组中,计算所有非相邻元素的和,并且该结果是所有结果中最大的。
思路1:先将数组排序;当数组大小为奇数时,取奇数位元素并相加;当数组大小为偶数则取偶数位元素并相加。(该思路是错误的,因为不能改变原有元素序列,实际上也无法移动房子的位置)
思路2:利用穷举法,将所有的可能结果都计算出来,并挑选出最大值。
2.个人解法
int rob(vector<int>& nums)
{
int res = 0;
int n = nums.size();
if(n == 2)
return max(nums[0], nums[1]);
else if(n == 1)
return nums[0];
for (int step = 2; step < n; ++step){
for(int i = 0; i<n; ++i){
int tmp = 0;
for(int j=i; j<n; j += step){
tmp += nums[j];
}
if(tmp > res)
res = tmp;
}
}
return res;
}
该解法并不能通过所有的测试用例,而且该解法的效率也非常低。
3.参考解法
int rob(vector<int>& nums)
{
if (nums.size() == 0) return 0;
if (nums.size() == 1) return nums[0];
if (nums.size() == 2) return max(nums[0], nums[1]);
int prev1 = nums[1], prev2 = nums[0], prev1_no_rob = nums[0], cur;
for (int i = 2; i < nums.size(); i++)
{
cur = max(prev1_no_rob + nums[i], max(prev1, prev2 + nums[i]));
prev1_no_rob = max(prev2, prev1);
prev2 = prev1;
prev1 = cur;
}
return cur;
}
该解法采用了动态规划方法,结果显示能够通过所有的测试用例,时间复杂度为O(n),空间复杂度为O(1)。
4.总结
由代码的结构可以看出,动态规划是解决该问题最简洁的方法。但由于自己对动态规划的思想和设计方面都不熟,所有也就没有想到该问题是一个简单的DP问题。
PS:
- 题目的中文翻译是本人所作,如有偏差敬请指正。
- 其中的“个人分析”和“个人解法”均是本人最初的想法和做法,不一定是对的,只是作为一个对照和记录。