打劫房屋III

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了打劫房屋III相关的知识,希望对你有一定的参考价值。

打劫房屋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]);
}

 

以上是关于打劫房屋III的主要内容,如果未能解决你的问题,请参考以下文章

LintCode刷题——打劫房屋IIIIII

Leetcode题目337:打家劫舍 III(中等)

LeetCode-动态规划打家劫舍 III

[LeetCode] 337. 打家劫舍 III (树形dp)

337. 打家劫舍 III

Lintcode--011(打劫房屋2)