LeetCode刷题EASY篇 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.

我的思路

分析一下,这个题目就是不连续抢劫,但是间隔不一定是1,可以大于1,只要不连续就可以。第二个房子抢不抢劫,依赖于第一个抢劫不抢劫,很明显是个DP动态规划问题。但是这个动态转化方程我没有找到,这是DP问题的核心。leetcode上有完美的代码,但没有说明,我详细解释一下思路,方便初学者容易理解。

如何找到状态转化方程:

1. 建立一个二维数组,行表示house的数目也就是nums的大小。列有两列,一个表示抢劫的情况下,money多少,一个是不抢劫的情况下money多少,以[1,2,3,1]数组为例,dp的记录表结构如下,四行两列的二维数组,初始值都为0,记录每家被抢劫和不被枪的时候money的数目

                                                      不被抢劫money数目                                被抢劫money数目

   
   
   
   

2. 转化方程

对于第二家,有两种情况,被抢劫和不抢劫。分开分析

  • 如果被抢劫,那么第一家肯定不被抢劫,因为会报警。此时dp[2][1]=nums[1]+dp[1][0]。解释一下这个方程,dp[2][1]表示第二家被抢劫的时候money的最大值,等于第二家的money数目+第一家不被抢劫的最大值。没有问题!这个是关键!
  • 如果不被抢劫,那么第一家可能被抢劫,也可能不被抢劫。所以,此时dp[2][0]等于两种情况的最大值。方程为dp[2][0]=max(dp[1][1],dp[1][0]);

3. 比较

最后比较最后两个元素的最大值就是我们所求的结果。

代码实现:

class Solution {
    public int rob(int[] nums) {
        int[][] dp=new int[nums.length][2];
        for(int  i=1;i<=nums.length;i++){
            //不被抢劫的情况
            dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]);
            //被抢劫的情况
            dp[i][1]=nums[i]+dp[i-1][0];
        }
        return Math.max(dp[nums.length][0],dp[nums.length][1]);
        
    }
}

调试发现有数组越界问题,仔细一看,nums[i]有问题。修改后发现6line还是越界,发现问题还出现在dp上,dp的第一个下标是i,从1开始,dp数组初始化为nums的长度,从0开始,所以不够,需要加1.

通过代码如下:

class Solution {
    public int rob(int[] nums) {
        int[][] dp=new int[nums.length+1][2];
        for(int  i=1;i<=nums.length;i++){
            //不被抢劫的情况
            dp[i][0]=Math.max(dp[i-1][0],dp[i-1][1]);
            //被抢劫的情况
            dp[i][1]=nums[i-1]+dp[i-1][0];
        }
        return Math.max(dp[nums.length][0],dp[nums.length][1]);
        
    }
}

如果要求O(1)的存储空间呢?理解DP思路之后,很容易就转化,这种转化主要是利用变量,不停更新存储最新的值。类似以前文章中斐波那契数列数列的动态规划思路,如果有读者不理解,可以翻阅我以前的leetcode系列找到。

再来,这个题目:

class Solution {
    public int rob(int[] nums) {
        int preYes=0;
        int preNo=0;
        for(int  i=1;i<=nums.length;i++){
            //先保存preNo,否则会被重新赋值
            int tmp=preNo;
            //不被抢劫的情况
            preNo=Math.max(preYes,preNo);
            //被抢劫的情况
            preYes=nums[i-1]+tmp;
        }
        return Math.max(preYes,preNo);
        
    }
}

猜你喜欢

转载自blog.csdn.net/hanruikai/article/details/84967076