198. House Robber*

198. House Robber*

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

題目描述

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.

Example 1:

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.

Example 2:

Input: [2,7,9,3,1]
Output: 12
Explanation: Rob house 1 (money = 2), rob house 3 (money = 9) and rob house 5 (money = 1).
             Total amount you can rob = 2 + 9 + 1 = 12.

C++ 實現 1

由於最後是求極值 (max/min), 我們要考慮用 DP 來做. 那麼首先就需要找到狀態以及狀態間的轉移方程, 說白點就是遞推公式. 根據經驗, 我們容易設置 f[i] 表示如果搶劫了第 i 個房子所能獲得的最大收益(即第 i 個房子必須搶). 而限制條件是, 如果搶劫了第 i 個房子, 那麼就不能搶劫它的鄰居, 即第 i - 1 個房子. 但是, 卻可以搶劫第 i - 2, i - 3, …, 0 個房子, 那麼我們就能得到遞推公式爲:

f[i] = nums[i] + max(f[i-2], f[i-3], ..., f[0])

f[i] 是由搶劫了其他房子所獲得的最大收益加上搶劫當前房子所獲得的收益得到的.

注意最後輸出是 f 中的最大值.

class Solution {
public:
    int rob(vector<int>& nums) {
        if (nums.empty()) return 0;
        if (nums.size() == 1) return nums[0];
        int n = nums.size();
        vector<int> f(n, 0);
        f[0] = nums[0];
        f[1] = nums[1];
        for (int i = 2; i < n; ++ i) {
            int imax = 0;
            for (int j = i - 2; j >= 0; -- j) imax = std::max(imax, f[j]);
            f[i] += imax + nums[i];
        }
        return *std::max_element(f.begin(), f.end());
    }
};

C++ 實現 2

也可以這樣理解: 題中要求是不能盜竊相鄰的兩家, 也就是盜竊了第 0 家, 那麼就不能盜竊第 1 家了, 另外, 也不一定會盜竊第二家. 設狀態 f(index) 表示盜竊 [index, ... n - 1] 範圍內的屋子所獲得的最大財物, 那麼我們要求 f(0), 狀態轉移方程爲:

f(0) = max(v(0) + f(2), v(1) + f(3), ... 
			v(n - 3) + f(n - 1), v(n - 2), v(n - 1))

如果只盜竊第 n - 2 家的話, 那麼第 n - 1 家就不能盜竊了, 所得到的財物數額就是 v(n - 2).

class Solution {
public:
    int rob(vector<int>& nums) {
        if (nums.empty())
            return 0;
        
        int n = nums.size();
        if (n == 1) return nums[0];
        if (n == 2) return max(nums[0], nums[1]);
        vector<int> f(n, 0);
        f[n - 1] = nums[n - 1];
        f[n - 2] = max(nums[n - 2], nums[n - 1]);
        for (int i = n - 3; i >= 0; i--) {
        	f[i] = max(f[i + 1], f[i + 2] + nums[i]);
        }
        return f[0];
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章