码迷,mamicode.com
首页 > 其他好文 > 详细

打劫房屋I、II

时间:2016-06-26 15:21:36      阅读:235      评论:0      收藏:0      [点我收藏+]

标签:

打劫房屋I 题目

假设你是一个专业的窃贼,准备沿着一条街打劫房屋。每个房子都存放着特定金额的钱。你面临的唯一约束条件是:相邻的房子装着相互联系的防盗系统,且 当相邻的两个房子同一天被打劫时,该系统会自动报警

给定一个非负整数列表,表示每个房子中存放的钱, 算一算,如果今晚去打劫,你最多可以得到多少钱 在不触动报警装置的情况下

挑战 : 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 long houseRobber(int[] A) {
    int len = A.length;
    if(len==0)
        return 0;
    // dp[i] 表达打劫i房间为止所活动的收获 ,与dp[i-2] dp[i-3]有关
    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[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]);
}

 

(二)不用数组。O(n) 时间复杂度 且 O(1) 存储

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

public long houseRobber(int[] A){
    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, max1, max2, max3;
    max0 = A[0];
    max1 = A[1];
    max2 = Math.max(max1, A[2]+max0);
    max3 = 0;
    for(int i=3; i<len; i++){
        max3 = A[i] + Math.max(max0, max1);
        max0 = max1;
        max1 = max2;
        max2 = max3;
    }
    return Math.max(max3, max1);
}

 

 打劫房屋II 题目

在上次打劫完一条街道之后,窃贼又发现了一个新的可以打劫的地方,但这次所有的房子围成了一个圈,这就意味着第一间房子和最后一间房子是挨着的。每个房子都存放着特定金额的钱。你面临的唯一约束条件是:相邻的房子装着相互联系的防盗系统,且 当相邻的两个房子同一天被打劫时,该系统会自动报警

给定一个非负整数列表,表示每个房子中存放的钱, 算一算,如果今晚去打劫,你最多可以得到多少钱 在不触动报警装置的情况下。

 

解题:

根据题目,第0个房间和第n-1个房间只能打劫其中一个

打劫范围只能是:0-n-2 或者1-n-1

所以根据打劫房间I的程序,修改为根据范围进行打劫,再求这个两个打劫的最大值。

public int houseRobber2(int[] nums) {
    // write your code here
    if(nums==null || nums.length==0)    return 0;
    int len = nums.length;
    if(len==1)  return nums[0];
    if(len==2)  return Math.max(nums[0], nums[1]);
    if(len==3)  return Math.max(Math.max(nums[1], nums[0]), nums[2]);
    int res1 = houseRobber(nums, 0, len-2);
    int res2 = houseRobber(nums, 1, len-1);
    return Math.max(res1, res2);
}

// 打劫房屋I(打劫范围)
private int houseRobber(int[] nums, int start, int end){
    if(start==end)  return nums[start];
    if(start+1 == end)  return Math.max(nums[start], nums[end]);
    if(start+2 == end)
        return Math.max(nums[start+1], nums[start]+nums[end]);
    
    int len = nums.length;
    int[] dp = new int[len];
    dp[start] = nums[start];
    dp[start+1] = nums[start+1];
    dp[start+2] = nums[start+2] + dp[start];
    for(int i=start+3; i<=end; i++){
        dp[i] = nums[i] + Math.max(dp[i-2], dp[i-3]);
    }
    return Math.max(dp[end], dp[end-1]);
}

 

打劫房屋I、II

标签:

原文地址:http://www.cnblogs.com/hesier/p/5617858.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!