leetcode 198 & 213:House Robber

一.House Robber I 的题意是:有一排商铺,强盗不能连续抢劫相邻的两家,否则会触动报警器,求强盗在不触动报警器的前提下,可以抢劫的最多金钱总和。(输入一维数组,从中选择若干个数,使得这些数的和最大,并且这些数互不相邻):

本题可以用两种方法解决:自顶向下(递归,直观)和自底向上(递推,动态规划的思想,时复低于前者),先介绍递归方法,我们可以认为有n个商铺,走到第m家商铺面,能获得的最大金额总和为两种情况中的最大值:Math.max(nums[m]+solve(m-2),solve(m-1)),所以代码如下:

public static int rob1(int[] nums) {
    return solve(nums.length-1,nums);
}
private static int solve(int index, int[] nums) {
	if(index <0 ){
		return 0;
	}
	int max = Math.max(nums[index]+solve(index-2,nums), solve(index-1,nums));
	return max;
}
这种方法非常耗时,因为有很多冗余计算(画个图便可以看出),所以改用第二中方法,动态规划。我们开一个数组,记录那些已经算过的子问题的解,这样就只需查数组不需要计算多次,所以将递归改为递推,递推公式基本不变,代码如下:

public class Solution {
    private int[] result;
    public int rob(int[] nums) {
        if(nums.length<=0){
            return 0;
        }
        if(nums.length==1){
            return nums[0];
        }
        int length = nums.length;
        result = new int[length];  //result数据用于记录子问题的解,然后递推
        result[0] = nums[0];       //以下两行定义边界情况
        result[1] = Math.max(nums[0],nums[1]);
        for(int i=2;i<length;i++){        //开始递推,递推公式没变
            result[i] = Math.max(nums[i]+result[i-2],result[i-1]);
        }
        return result[length-1];
    }
}
二. House Robber II的题意是:这些商铺不是一排了,而是围成了一个圈,这样以前数组的第一个元素与最后一个元素也变成相邻的,其他要求不变,仍然是找出若干个不相邻的数,使他们的和最大。

思路:这道题在上一道的基础上加了限制,即抢了第一家就不能抢最后一家,抢了最后一家就不能抢第一家。所以分为两种情况分别进行计算,最后返回这两种情况中结果最大一个即为所求,我们这次要开两个数组,分别记录这两种情况的子问题的题,其他地方思路不变(边界的定义,递推公式均不变,只是数组为两个不同的数组而已),代码如下:

public class Solution {
    public int rob(int[] nums) {
        if(nums.length <=0)
        	return 0;
        if(nums.length ==1)
        	return nums[0];
        if(nums.length ==2)
        	return Math.max(nums[0], nums[1]);
        int[] dp1 = new int[nums.length-1];  //记录第1个到倒数第2个
        int[] dp2 = new int[nums.length-1];  //记录第2个到倒数第1个
        dp1[0] = nums[0];
        dp1[1] = Math.max(nums[0], nums[1]);
        dp2[0] = nums[1];
        dp2[1] = Math.max(nums[1], nums[2]);
        for(int i=2;i<nums.length-1;i++){
        	dp1[i] = Math.max(nums[i]+dp1[i-2], dp1[i-1]);
        	dp2[i] = Math.max(nums[i+1]+dp2[i-2], dp2[i-1]);
        }
        return Math.max(dp1[nums.length-2], dp2[nums.length-2]); 
    }
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值