[LeetCode] 213. House Robber II 打家劫舍之二


 

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.

Credits:
Special thanks to @Freezen for adding this problem and creating all test cases.

 

這道題是之前那道 House Robber 的拓展,現在房子排成了一個圓圈,則如果搶了第一家,就不能搶最后一家,因為首尾相連了,所以第一家和最后一家只能搶其中的一家,或者都不搶,那這里變通一下,如果把第一家和最后一家分別去掉,各算一遍能搶的最大值,然后比較兩個值取其中較大的一個即為所求。那只需參考之前的 House Robber 中的解題方法,然后調用兩邊取較大值,代碼如下:

 

解法一:

class Solution {
public:
    int rob(vector<int>& nums) {
        if (nums.size() <= 1) return nums.empty() ? 0 : nums[0];
        return max(rob(nums, 0, nums.size() - 1), rob(nums, 1, nums.size()));
    }
    int rob(vector<int> &nums, int left, int right) {
        if (right - left <= 1) return nums[left];
        vector<int> dp(right, 0);
        dp[left] = nums[left];
        dp[left + 1] = max(nums[left], nums[left + 1]);
        for (int i = left + 2; i < right; ++i) {
            dp[i] = max(nums[i] + dp[i - 2], dp[i - 1]);
        }
        return dp.back();
    }
};

 

當然,我們也可以使用兩個變量來代替整個 DP 數組,講解與之前的帖子 House Robber 相同,分別維護兩個變量 robEven 和 robOdd,顧名思義,robEven 就是要搶偶數位置的房子,robOdd 就是要搶奇數位置的房子。所以在遍歷房子數組時,如果是偶數位置,那么 robEven 就要加上當前數字,然后和 robOdd 比較,取較大的來更新 robEven。這里就看出來了,robEven 組成的值並不是只由偶數位置的數字,只是當前要搶偶數位置而已。同理,當奇數位置時,robOdd 加上當前數字和 robEven 比較,取較大值來更新 robOdd,這種按奇偶分別來更新的方法,可以保證組成最大和的數字不相鄰,最后別忘了在 robEven 和 robOdd 種取較大值返回,代碼如下:

 

解法二:

class Solution {
public:
    int rob(vector<int>& nums) {
        if (nums.size() <= 1) return nums.empty() ? 0 : nums[0];
        return max(rob(nums, 0, nums.size() - 1), rob(nums, 1, nums.size()));
    }
    int rob(vector<int> &nums, int left, int right) {
        int robEven = 0, robOdd = 0;
        for (int i = left; i < right; ++i) {
            if (i % 2 == 0) {
                robEven = max(robEven + nums[i], robOdd);
            } else {
                robOdd = max(robEven, robOdd + nums[i]);
            }
        }
        return max(robEven, robOdd);
    }
};

 

另一種更為簡潔的寫法,講解與之前的帖子 House Robber 相同,我們使用兩個變量 rob 和 notRob,其中 rob 表示搶當前的房子,notRob 表示不搶當前的房子,那么在遍歷的過程中,先用兩個變量 preRob 和 preNotRob 來分別記錄更新之前的值,由於 rob 是要搶當前的房子,那么前一個房子一定不能搶,所以使用 preNotRob 加上當前的數字賦給 rob,然后 notRob 表示不能搶當前的房子,那么之前的房子就可以搶也可以不搶,所以將 preRob 和 preNotRob 中的較大值賦給 notRob,參見代碼如下:

 

解法三:

class Solution {
public:
    int rob(vector<int>& nums) {
        if (nums.size() <= 1) return nums.empty() ? 0 : nums[0];
        return max(rob(nums, 0, nums.size() - 1), rob(nums, 1, nums.size()));
    }
    int rob(vector<int> &nums, int left, int right) {
        int rob = 0, notRob = 0;
        for (int i = left; i < right; ++i) {
            int preRob = rob, preNotRob = notRob;
            rob = preNotRob + nums[i];
            notRob = max(preRob, preNotRob);
        }
        return max(rob, notRob);
    }
};

 

Github 同步地址:

https://github.com/grandyang/leetcode/issues/213

 

類似題目:

House Robber

House Robber III

Paint House

Paint Fence

Non-negative Integers without Consecutive Ones

Coin Path

 

參考資料:

https://leetcode.com/problems/house-robber-ii/

https://leetcode.com/problems/house-robber-ii/discuss/59929/Java-clean-short-solution-DP

https://leetcode.com/problems/house-robber-ii/discuss/59934/Simple-AC-solution-in-Java-in-O(n)-with-explanation

 

LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM