198. 打家劫舍

198. 打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

示例 1:

输入:[1,2,3,1]
输出:4
解释:偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4 。

示例 2:

输入:[2,7,9,3,1]
输出:12
解释:偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12 。

题解:
打家劫舍是经典的动态规划题,老样子咱么还是用卡哥的动归五部曲。
1、确定 dp 数组的下标及含义
dp[i] 表示 0 - i 包括 i 以内最多可以偷窃到的金额。

2、递归公式
上述题目说了,我们必须隔着一个屋子偷窃,那么决定 dp[i] 的因素也就是,是否跳过第 i 个房间。
如果跳过那么 dp[i] = dp[i-1] ,跳过自然不能把 i 算在里面,dp[i-1]表示的是 0 - i-1 包括 i-1 以内最多可以偷窃到的金额,而不是一定要偷 i-1 房,那么如果不跳过,dp[i] = dp[i-2] + num[i] ,偷 i 那么就说明 不偷 i-1 ,必然是偷了 i -2 ,再加上咱们的 i ,就是dp[i] 最大的偷窃金额。
如上所述,递推公式为:
dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]) 我们需要的是最大金额,所以需要在其中选一个出来,你只能选择偷 i 或者不偷 i,不能同时选择哦。所以是选其中大的一个。

3、初始化 dp 数组
从递推公式我们可以看出来,dp[i-2] 就需要有 dp[0] ,dp[1] 的支撑,从 dp[i] 的定义上来讲,dp[0] 一定是 nums[0],dp[1]就是 nums[0] 和 nums[1] 的最大值即:dp[1] = max(nums[0], nums[1]);因为我们需要最大嘛。

4、确定遍历顺序
这很明显了,正常遍历即可。

5、推导dp 数组
这里一般就是画图推导,但是我懒,建议写出代码,然后 debug 看,验证自己的猜想。

代码:

	public int rob(int[] nums) {
        //判空
        if (nums == null || nums.length == 0) return 0;
		if (nums.length == 1) return nums[0];
        //定义dp数组
		int[] dp = new int[nums.length];
        //初始化dp数组
		dp[0] = nums[0];
		dp[1] = Math.max(dp[0], nums[1]);
        //遍历
		for (int i = 2; i < nums.length; i++) {
            //递推公式
			dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
		}
        //返回结果,返回数组的最后一个因为我们是逐个加过来的
		return dp[nums.length - 1];
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值