Problem statement:
Note: This is an extension of House Robber.
After robbing those houses on that street, the thief has found himself a new place for his thievery so that he will not get too much attention. This time, all houses at this place are arranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, the security system for these houses remain the same as for those in the previous street.
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.
Analysis:
As mentioned in the description, it is an extension of 198. House Robber. It limits that the first and last houses are also adjacent.
Solution one: DP(AC)
This is my first solution. It shares the same DP formula with 198. House Robber. Since we can choose to rob the first house or not rob the first.
So, do two times dynamic programming. the differences are the initialized value and return value.
First DP we suppose to rob the frist house, so r1[i] = nums[0], n1[i] = 0. Only return n1[size - 1]
Second DP suppose not to rob the first house, r2[i] = 0, n2[i] = 0. Return max(r2[size - 1], n2[size - 1]).
The final result is max(n1[size - 1], max(r2[size - 1], n2[size - 1])).
Corner case: just return nums[0] if (nums.size() == 1);
Time complexity is O(2 * n) ---> O(n).
class Solution { public: int rob(vector<int>& nums) { if(nums.empty()){ return 0; } if(nums.size() == 1){ return nums[0]; } int size = nums.size(); // rob the first house // only return not_rob int r1 = nums[0]; int n1 = 0; for(int i = 1; i < size; i++){ int r = r1; int n = n1; r1 = nums[i] + n; n1 = max(r, n); } // do not rob the first house. int r2 = 0; int n2 = 0; for(int i = 1; i < size; i++){ int r = r2; int n = n2; r2 = nums[i] + n; n2 = max(r, n); } return max(n1, max(r2, n2)); } };
Solution two: DP(AC).
This solution comes from leetcode discussion. In fact, there is no bigger difference with my solution. It smartly chooses the start and end position to decide how to solve the adjacent of first and last elements.
It looks concise, and the explanations are clear and simple, it follows computer methodology. I like this thinking process. Because not strong, I need more practice.
Time complexity is O(n).
class Solution { public: int rob(vector<int>& nums) { if(nums.size() == 1){ return nums[0]; } return max(max_rob(nums, 0, nums.size() - 2), max_rob(nums, 1, nums.size() - 1)); } private: int max_rob(vector<int>& nums, int start, int end){ int rob = 0, not_rob = 0; for(int i = start; i <= end; i++){ int r = rob; int n = not_rob; rob = nums[i] + n; not_rob = max(r, n); } return max(rob, not_rob); } };