题目
假设你是一个专业的窃贼,准备沿着一条街打劫房屋。每个房子都存放着特定金额的钱。你面临的唯一约束条件是:相邻的房子装着相互联系的防盗系统,且 当相邻的两个房子同一天被打劫时,该系统会自动报警。
给定一个非负整数列表,表示每个房子中存放的钱, 算一算,如果今晚去打劫,你最多可以得到多少钱 在不触动报警装置的情况下。
样例
给定 [3, 8, 4]
, 返回 8
.
挑战
Java Code
Java Code
Python Code
O(n) 时间复杂度 且 O(1) 存储。
解题
定义dp[i]表示打劫第i个房间为止所获得的最大收益,而dp[i]的值只与dp[i-2] 和dp[i-3]有关 并且 dp[i] = A[i] + max(dp[i-2],dp[i-3])
当求解所有的A[i]后,需要对最后两个dp[len-1] dp[len-2] 取最大值作为最后的答案。参考链接
public class Solution { /** * @param A: An array of non-negative integers. * return: The maximum amount of money you can rob tonight */ public long houseRobber(int[] A) { // write your code here int len = A.length; // dp[i] 表达打劫i房间为止所活动的收获 ,与dp[i-2] dp[i-3]有关 if(len ==0) return 0; long dp[] = new long[len]; dp[0] = A[0]; if(len == 1){ return dp[0]; }else if(len == 2){ dp[1] = A[1]; return Math.max(dp[0],dp[1]); }else if(len == 3){ dp[1] = A[1]; dp[2] = A[0] + A[2]; return Math.max(dp[1],dp[2]); } dp[1] = A[1]; dp[2] = A[0] + A[2]; for(int i = 3;i< len; i++){ dp[i] = A[i] + Math.max(dp[i-2],dp[i-3]); } return Math.max(dp[len-2],dp[len-1]); } }
总耗时: 3790 ms
不用数组,更改后的程序如下
public class Solution { /** * @param A: An array of non-negative integers. * return: The maximum amount of money you can rob tonight */ public long houseRobber(int[] A) { // write your code here int len = A.length; if(len == 0) return 0; if(len == 1) return A[0]; if(len == 2) return Math.max(A[0],A[1]); if(len == 3) return Math.max(A[1],A[0] + A[2]); long max0 = 0; long max1 = 0; long max2 = 0; long max3 = 0; max1 = A[0]; max2 = A[1]; for(int i = 2;i< len ;i++){ max3 = A[i] + Math.max(max0,max1); max0 = max1; max1 = max2; max2 = max3; } return Math.max(max3,max1); } }
讲解
i-3 | i-2 | i-1 | i | ||
max0 | max1 | max2 | max3 |
对第i处的最大值max3 = A[i] + max(max1,max0)
当是i+1个的时候,更新max0、max1、max2
max0 = max1
max1 = max2
max2 = max3
主要对前三个的A[i]需要进行单独处理。
写成Python
class Solution: # @param A: a list of non-negative integers. # return: an integer def houseRobber(self, A): # write your code here lenA = len(A) if A == []: return 0 if lenA == 1: return A[0] if lenA == 2: return max(A[0],A[1]) dp = [0]*lenA dp[0] = A[0] dp[1] = A[1] dp[2] = A[2] + A[0] for i in range(3,lenA): dp[i] = A[i] + max(dp[i-2],dp[i-3]) return max(dp[lenA-1],dp[lenA-2])
总耗时: 814 ms
网上看到,也可以这样定义dp[i],表示当前所能获得的最大收获,这里的值最终就是最大值,由于数组dp的长度是len+1,第一个元素是0,dp[i]也可以理解为,不包含A[i]元素时所取得的最大值。
public class Solution { /** * @param A: An array of non-negative integers. * return: The maximum amount of money you can rob tonight */ public long houseRobber(int[] A) { // write your code here int len = A.length; if(len == 0) return 0; long dp[] = new long[len+1]; dp[1] = A[0]; if(len == 1) return dp[1]; for(int i= 2 ;i<= len ;i++){ dp[i] = Math.max(dp[i-1],dp[i-2] + A[i-1]); } return dp[len]; } }
不要数组
public class Solution { /** * @param A: An array of non-negative integers. * return: The maximum amount of money you can rob tonight */ public long houseRobber(int[] A) { // write your code here int len = A.length; if(len == 0) return 0; long res1 = 0; long res2 = A[0]; if( len == 1) return res2; for(int i=1;i<len ;i++){ long res3 = Math.max(res2,res1+A[i]); res1 = res2; res2 = res3; } return res2; } }