leetcode [Dynamic Programming] No.231 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.

解题思路

首先我们考虑一种简单的情况,我们假设第一家商店和最后一家商店不是相连的(即我们可以同时抢劫第一家和最后一家而不触发警报)。在这种情况下,我们用 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(n1),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 n1家商店的收益(因为我们不能再抢劫第 n n n加商店了,否则会触发警报);若不抢劫,则收益和抢劫前 n n n家商店的收益一样,更新 F ( n + 1 ) F(n+1) F(n+1)时,我们只需要取这两者的最大值。

接下来我们考虑完整的问题,若第一家商店和最后一家商店相连,那么我们可以应用类似的思想:若我们抢劫第一家商店,则我们就不可以抢劫最后一家商店,所以我们可以将问题转化为抢劫前 n − 1 n-1 n1家商店,且首尾商店不相连时的最大收益,这就转化成了上述简化的问题;若我们不抢劫第一家商店,则问题又可以转化为抢劫后 n − 1 n-1 n1家商店,且首尾商店不相连时的最大收益,同样转化成了上述简化的问题。最后我们只需要取两次计算结果中的最大值即是答案。

代码:

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),已经是很高效的算法了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值