LintCode 打劫房屋 I II III

打劫房屋 I

LintCode 打劫房屋

思路:

採用動態規劃思想,小偷從第一個房子開始依次向後移動,設截止到第i個房子時的最大獲利爲f(i)。

移動到第 i 個房子時,有兩種選擇:打劫第i個房屋,則第i-1個房子不能打劫,因此截止目前獲利爲 money[ i ] + f(i-2);不打劫第i個房子,則第i-1個房子可以打劫,所以截止目前獲利爲f(i-1)。到底要不要打劫第i個房子取決於二者獲利誰更大,所以有f[n]=max( f[n-1], f[n-2]+money[n] )。

代碼:

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 n = A.length;
        if(n == 0)
            return 0;
        if(n == 1)
            return A[0];
            
        long[] dp = new long[n];
        dp[0] = A[0];                   //打劫至第一個房子的最大收益
        dp[1] = Math.max(A[0], A[1]);   //打劫至第二個房子的最大收益
        for(int i = 2; i < n; i++) {
            dp[i] = Math.max(dp[i-1], dp[i-2] + A[i]);   //打劫至第i+1個房子的最大收益
        }
        return dp[n-1];
    }
}

因爲dp[n]只與dp[n-1]和dp[n-2]有關,因此只保存兩個變量即可。

代碼優化爲:

    public long houseRobber(int[] A) {
        // write your code here
        int n = A.length;
        long pre2 = 0, pre1 = 0;
        long ans = 0;
        for(int i = 0; i < n; i++) {
            ans = Math.max(pre2 + A[i], pre1);
            pre2 = pre1;
            pre1 = ans;
        }
        return ans;
    }

tip:這樣寫就不用單獨考慮n=0和n=1的情況。

參考:https://blog.csdn.net/ljlstart/article/details/48413325


打劫房屋 II

LintCode 打劫房屋 II

思路:與上一題相比,區別在於由直線變成了環形,第一個房子和最後一個房子不能同時打劫。假設房子編號1~n,分兩種情況處理:

第一種,放棄最後一間房子,只打劫編號 1~ (n-1) 的房子,最大收益記爲a;

第二種,放棄第一間房子,只打劫編號 2 ~ n 的房子,最大收益記爲b。

則 a , b 中的較大值即爲答案。

代碼:

public class Solution {
    /**
     * @param nums: An array of non-negative integers.
     * @return: The maximum amount of money you can rob tonight
     */
    public int houseRobber2(int[] nums) {
        // write your code here
        int n = nums.length;
        if(n == 0)
            return 0;
        if(n == 1)
            return nums[0];
            
        int a = sub(nums, 0, n-2); //放棄最後一間房子
        int b = sub(nums, 1, n-1); //放棄第一間房子
        return Math.max(a, b);
    }
    
    //打劫範圍從nums[start]到nums[end],須保證start <= end
    private static int sub(int[] nums, int start, int end) {
        int n = nums.length;
        int pre2 = 0, pre1 = 0;
        int ans = 0;
        for(int i = start; i <= end; i++) {
            ans = Math.max(pre2 + nums[i], pre1);
            pre2 = pre1;
            pre1 = ans;
        }
        return ans;
    }
}

打劫房屋 III

LintCode 打劫房屋 III

方法一:

這道題和上兩題不同,不能用動態規劃,而是用遞歸。

public class Solution {
    /**
     * @param root: The root of binary tree.
     * @return: The maximum amount of money you can rob tonight
     */
    
    // 遞歸方法
     Map<TreeNode, Integer> map = new HashMap<>(); //避免重複計算
     
    //打劫以root爲根節點的二叉樹,返回最大收益錢數
    public int houseRobber3(TreeNode root) {
        // write your code here
        if(root == null)
            return 0;
        if(map.containsKey(root))
            return map.get(root);
        
        //打劫根節點,總錢數記爲a
        int a = root.val;
        if(root.left != null) {
            a += houseRobber3(root.left.left);
            a += houseRobber3(root.left.right);
        }
        if(root.right != null) {
            a += houseRobber3(root.right.left);
            a += houseRobber3(root.right.right);
        }
        
        //不打劫根節點,總錢數記爲b
        int b = houseRobber3(root.left) + houseRobber3(root.right);
        
        map.put(root, Math.max(a,b));
        return Math.max(a, b);  //返回a和b中的較大值
    }
}

方法二:

http://www.aichengxu.com/other/6568545.htm

方法三:

https://blog.csdn.net/zaqwsx20/article/details/70156192  (沒看懂)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章