题目链接:
题目描述:
打家劫舍
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你在不触动警报装置的情况下,能够偷窃到的最高金额。
示例 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 。
解决方案:
本题可以用线性动态规划解决,小偷偷几家是没有限制的,只规定了不能偷相邻的房屋,也就是说想要偷窃金额最大化,必然是隔一个偷一家。
设 dp[i] 为偷到第 i 个房屋时的最高金额(第 i 家可能偷可讷能不偷,取最高金额),如果偷第 i-1 家,就不能偷第 i 家:
dp[i] = Max(dp[i-2]+nums[i], dp[i-1])
返回的结果即dp[nums.length-1]。
本题是一道简单的动态规划问题,直接给出优化后的解决方案。
优化:不开辟新的数组空间,只用nums[]本身。在计算 dp[i] = Max(dp[i-2]+nums[i], dp[i-1]) 时,可以看到每次会用到的是更新后的nums[i-2]和nums[i-1](更新后记录的是dp),以及没更新的nums[i]。
代码:
/*
*线性动态规划,设 dp[i] 为偷到第 i 个房屋时的最高金额
*如果偷第 i-1 家,就不能偷第 i 家
*dp[i] = Max(dp[i-2]+nums[i], dp[i-1])
*返回的结果即dp[nums.length-1]
*优化:不开辟新的数组空间,只用nums[]本身
*每次会用到的是更新后的nums[i-2]和nums[i-1](更新后记录的是dp)
*以及没更新的nums[i]
*/
class Solution {
public int rob(int[] nums) {
if(nums.length < 1){ return 0;}
if(nums.length < 2){ return nums[0];}
if(nums.length < 3){ return Math.max(nums[0], nums[1]);}
nums[1] = Math.max(nums[0], nums[1]);
for(int i = 2; i < nums.length; i++){
nums[i] = Math.max(nums[i-2] + nums[i], nums[i-1]);
}
return nums[nums.length-1];
}
}
提交截图:
执行用时在Java提交中击败了100%的用户,这个估计大家都是一样的。说实话这个内存消耗我一直没看明白,前面两次提交的代码是一模一样的,只是改了改格式(在 if 后面的 return 前加了空格),结果内存消耗就变成了 37.1 MB,比第一次提交创建了一个新的一位数组 dp[] 用的内存消耗还大…个人觉得已经没有开辟新的空间了,只用了题目里给出的 nums[],在空间上没有什么好进一步优化了,本题也可以告一段落了。