LeetCode --- House Robber & House Robber II

来源:互联网 发布:jsp页面读取数据库 编辑:程序博客网 时间:2024/05/05 03:44

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