LeetCode 198 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.

题意是这样的,有一个强盗,要去抢一条街的店铺。在抢的时候,不能抢紧挨着的两家店,给出每个店能抢到的数额,问:能抢到的最大值是多少。

首先,思路是这样的:我们可以先从最后一家店开始抢,设坐标为index,那么接下来的那家店的坐标只能是index-2或index-3等等。如果我们从倒数第二家开始抢,那么他抢的第一家的坐标就是index-1,那么下面抢的店家坐标就只能是index-3或index-4等等。。。我们可以写出这样一个递归式:

public int solve(int index,int[] nums){
        result[index] = Math.max(nums[index]+solve(index-2,nums),solve(index-1,nums));
        return result[index];
    }

对于这个递归式,我们就是要找出两次之前的最大值并返回。我们队里面的参数一个一个解释一遍,nums[index]可以理解为从最后一个位置开始抢的数额,那么他的下一个要抢的就是solve(index-2,nums), 在对solve(index-1,nums)说出我的理解:就是抢东西的另一种情况了。从index-1家店开始抢。然后找出这两次的最大值就可以了,就是这个强盗要抢的最大值了。

但是,对于递归来说,都有一个递归深度,所以我们必须要设置一个底,就是当index<0时,本次递归结束,网上返回,所以代码就变成这样

 public int solve(int index,int[] nums){
        
        if(index < 0){
            return 0;
        }
        
        result[index] = Math.max(nums[index]+solve(index-2,nums),solve(index-1,nums));
        return result[index];
    }
但是,这样的时间复杂度太高了,我们算了好多冗余,所以我们要去冗余。我们分析一下,都有哪些冗余,比如用第一种情况开始抢时,那么他的下一家就是index-2或index-3或index-4.....  第二种情况是就是下一家要抢的就是 index-3或index-4....我们可以看出,有好多药重复计算的部分,所以我们可以把计算过的设置一个标记位,如果碰到计算过的,就直接返回result[index]。做标记时,我们可以这样, ,new出来一个数组result,长度为nums.length,把每个result的值都设置为-1。

 for(int i=0;i<nums.length;i++){
            result[i]=-1;
        }

所以,我们的完整代码就可以写为:
class Solution {
    private static int[] result;
    public int rob(int[] nums) {
        result = new int[nums.length];
        for(int i=0;i<nums.length;i++){
            result[i]=-1;
        }
        return solve(nums.length-1,nums);
        
    }
    
    public int solve(int index,int[] nums){
        
        if(index < 0){
            return 0;
        }
        
        if(result[index] >= 0){
            return result[index];
        }
        
        result[index] = Math.max(nums[index]+solve(index-2,nums),solve(index-1,nums));
     //   result[index] = Math.max(solve(index,nums),solve(index-1,nums));
        return result[index];
    }
    
}
这样的代码是能AC的。

但是,到这里我还有一个问题,就是在写

Math.max(nums[index]+solve(index-2,nums),solve(index-1,nums));这个时,不能写成

Math.max(nums[index]+solve(index-2,nums),num[index-1]+solve(index-3,nums));


这不就符合题意么?但是提交的时候,出现的是数组下标越界异常,我也没有深入的去尝试。。。。。

还有一种情况 Math.max(nums[index]+solve(index-2,nums),solve(index-1,nums));

不能写成 Math.max(solve(index,nums),solve(index-1,nums));

这种情况也是不能AC的,包的是栈溢出,我也没有深入的去理解。。。。太菜了我。。。。。。。。

我们还可以改写一下代码,不用递归。

class Solution {
    private static int[] result;
    public int rob(int[] nums) {
        result = new int[nums.length];
       
        if(nums.length == 0){
            return 0;
        }
        
        if(nums.length == 1){
            return nums[0];
        }
        
        result[0] = nums[0];
        result[1] = Math.max(nums[0],nums[1]);
        
        //注意边界问题
        for(int i=2;i<nums.length;i++){
             result[i] = Math.max(nums[i]+result[i-2],result[i-1]);
        }
        
        return result[nums.length-1]; 
    }
}
因为solve方法返回的值就算是result,所有把solve替换掉resulr,还有,注意边界问题,。

感觉韩式递归容易理解点。。。我也是学习别人给我讲的东西,有的东西我也不是太理解。。。。。。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值