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];
    }
};
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章