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.

这是一个很经典的动态规划的题目,意思是一个盗贼要偷盗一条街道上的店铺。唯一的限制就是不能同时偷盗连续的两家店铺,否则的话报警器就会被触发,求在不触发警报的情况下该盗贼可偷盗的最多金钱数。 

解题思路

  1. 用递归来解决

盗贼遍历店铺,从当前店铺开始获取的最大收益 = max(偷盗当前店铺获取的最大收益, 不偷盗当前店铺获取的最大收益)

代码如下:

public class Solution {
public int rob(int[] nums) {
return robber(nums, 0);
}
public int robber(int[] nums, int start) {
if(start > nums.length-1) return 0;
if(start == nums.length-1) return nums[start];
int result1 = 0, result2 = 0;
result1 = nums[start] + robber(nums, start+2);
result2 = robber(nums, start+1);
return result1 > result2 ? result1 : result2;
}
}

  
上面的代码时间复杂度较高。原因在于递归的时候一些中间的计算结果没有保存下来,导致多次计算已经计算后的结果。

  1. 此时我们将递归改写成循环,将一些中间的计算值保存下来,这就是动态规划思路

转态转移方程:dp[i] = max(dp[i - 1], dp[i - 2]) + num[i]

代码如下:

class Solution {
public int rob(int[] nums) {
if(nums==null || nums.length==0)
return 0;
if(nums.length == 1) return nums[0];
int[] dp = new int[nums.length];
dp[0] = nums[0];
dp[1] = Math.max(nums[0], nums[1]);
for(int i=2; i<nums.length; i++){
dp[i] = Math.max((dp[i-2]+nums[i]), dp[i-1]);
}
return dp[nums.length-1];
}
}

  
上面代码的空间复杂度为O(n),我们发现其实不必把已经计算过的所有信息保存下来,只要保存后两个记录即可,优化后的空间复杂度为O(1),代码如下:

public class Solution {
public int rob(int[] nums) {
int len = nums.length;
if(len == 0) return 0;
if(len == 1) return nums[0];
int post2 = nums[len-1];
int post1 = Math.max(nums[len-2], nums[len-1]);
for(int i = len-3; i >= 0; i--) {
int temp = post1;
post1 = Math.max(post1, nums[i] + post2);
post2 = temp;
}
return post1;
}
}
posted @ 2018-01-06 10:42  小丑进场  阅读(337)  评论(0)    收藏  举报