问题描述
You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed. All houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, 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.
Example 1:
Input: [2,3,2]
Output: 3
Explanation: You cannot rob house 1 (money = 2) and then rob house 3 (money = 2),
because they are adjacent houses.
Example 2:
Input: [1,2,3,1]
Output: 4
Explanation: Rob house 1 (money = 1) and then rob house 3 (money = 3).
Total amount you can rob = 1 + 3 = 4.
解题思路
首先我们考虑一种简单的情况,我们假设第一家商店和最后一家商店不是相连的(即我们可以同时抢劫第一家和最后一家而不触发警报)。在这种情况下,我们用 F ( n ) F(n) F(n)表示抢劫前 n n n家商店可以获得的最大收益,那么当问题规模扩展到 n + 1 n+1 n+1时,有 F ( n + 1 ) = m a x { f ( n + 1 ) + F ( n − 1 ) , F ( n ) } F(n+1) = max\{f(n+1) + F(n-1), F(n)\} F(n+1)=max{f(n+1)+F(n−1),F(n)}其中 f ( n ) f(n) f(n)表示抢劫第 n n n家商店的收益。当第 n + 1 n+1 n+1家商店被加入问题的时候,我们考虑是否抢劫第 n + 1 n+1 n+1家商店,若抢劫,则当前的最大收益应是第 n + 1 n+1 n+1家商店的收益加上前 n − 1 n-1 n−1家商店的收益(因为我们不能再抢劫第 n n n加商店了,否则会触发警报);若不抢劫,则收益和抢劫前 n n n家商店的收益一样,更新 F ( n + 1 ) F(n+1) F(n+1)时,我们只需要取这两者的最大值。
接下来我们考虑完整的问题,若第一家商店和最后一家商店相连,那么我们可以应用类似的思想:若我们抢劫第一家商店,则我们就不可以抢劫最后一家商店,所以我们可以将问题转化为抢劫前 n − 1 n-1 n−1家商店,且首尾商店不相连时的最大收益,这就转化成了上述简化的问题;若我们不抢劫第一家商店,则问题又可以转化为抢劫后 n − 1 n-1 n−1家商店,且首尾商店不相连时的最大收益,同样转化成了上述简化的问题。最后我们只需要取两次计算结果中的最大值即是答案。
代码:
class Solution {
public:
int rob(vector<int>& nums) {
if (nums.size() == 0) return 0;
if (nums.size() == 1) return nums[0];
vector<int> rob(nums.size());
int ret = 0;
rob[0] = nums[0];
rob[1] = max(nums[0], nums[1]);
for (int i = 2; i < nums.size() - 1; i++) {
rob[i] = max(nums[i] + rob[i - 2], rob[i - 1]);
}
ret = rob[nums.size() - 2];
rob[1] = nums[1];
rob[2] = max(nums[1], nums[2]);
for (int i = 3; i < nums.size(); i++) {
rob[i] = max(nums[i] + rob[i - 2], rob[i - 1]);
}
ret = max(ret, rob[nums.size() - 1]);
return ret;
}
};
运行结果:
通过对算法的分析我们可以得出,该算法的时间效率为
O
(
n
)
O(n)
O(n),已经是很高效的算法了。