LeetCode --- House Robber & House Robber II

House Roober

题目链接

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.

题目分析

假设当前我们已经到达第[i]个屋子,如图所示

HouseRobber

那是否偷第[i]个房子只和前面两个房子是否已经被偷过有关系

假设f(i)是,当前偷到第i个房子时,获取的最大值,那么我们可以得到如下的状态转移方程

HouseRobber Function

经典的DP问题,所以,代码如下:

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

House Robber II

题目链接

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

题目分析

首先街道已经变换为圆形,即首尾相接,那么是否偷第一个已经关系到最后一个是否偷取的问题。

注意上面加黑的一句话

  • 分析一

    让我们分三种情况考虑:

    • [1]号房子,那么[2]和[N]号不能再拿,另外[3…N-1]退化为了直线型
    • [N]号房子,那么[1]和[N-1]号不能再拿,另外[2…N-2]退化为了直线型
    • [1]和[N]号房子都不拿,那么[2…N-1]退化为了直线型

    所以按照这种情况考虑,代码如下:

class Solution {
public:
    int rob_line(vector<int>& nums, int start, int end) {
        if (start >= end) return 0;
        if (end - start == 1) return nums[start];
        vector<int> dp(end - start + 1, 0);
        int dp_ind = 1;
        dp[dp_ind] = nums[start];
        for (int i = start + 1; i < end; i++) {
            dp_ind++;
            dp[dp_ind] = max(nums[i] + dp[dp_ind - 2], dp[dp_ind - 1]);
        }
        return dp[dp_ind];
    }
    int rob(vector<int>& nums) {
        if (nums.size() == 0) return 0;
        return max(rob_line(nums, 1, nums.size() -1), 
            max(rob_line(nums, 2, nums.size() - 1) + nums[0], 
            rob_line(nums, 1, nums.size() - 2) + nums[nums.size() - 1]));
    }
};
  • 改进

    在上面的分析中,我们强制取[1]或[N],其实我们把问题复杂化了,因为这样分析我们把动态性降低了,我们可以从相反的方向考虑,则只需要分二种情况即可,即

    • 不取[1]
    • 不取[N]

    那么剩余的房间,都可以转化为直线型,从而比上面的代码减少一个O(N)的时间

class Solution {
public:
    int rob_line(vector<int>& nums, int start, int end) {
        if (start >= end) return 0;
        if (end - start == 1) return nums[start];
        vector<int> dp(end - start + 1, 0);
        int dp_ind = 1;
        dp[dp_ind] = nums[start];
        for (int i = start + 1; i < end; i++) {
            dp_ind++;
            dp[dp_ind] = max(nums[i] + dp[dp_ind - 2], dp[dp_ind - 1]);
        }
        return dp[dp_ind];
    }

    int rob(vector<int>& nums) {
        if (nums.size() == 0) return 0;
        if (nums.size() == 1) return nums[0];
        return max(rob_line(nums, 0, nums.size() - 1), rob_line(nums, 1, nums.size()));
    }
};

备注:上述状态转移方程,当前状态只和前两个状态有关,存储空间可以压缩为O(1)的,读者自行实现吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值