Leetcode337 打家劫舍III

原題:

https://leetcode-cn.com/problems/house-robber-iii/submissions/

在上次打劫完一條街道之後和一圈房屋後,小偷又發現了一個新的可行竊的地區。這個地區只有一個入口,我們稱之爲“根”。 除了“根”之外,每棟房子有且只有一個“父“房子與之相連。一番偵察之後,聰明的小偷意識到“這個地方的所有房屋的排列類似於一棵二叉樹”。 如果兩個直接相連的房子在同一天晚上被打劫,房屋將自動報警。
計算在不觸動警報的情況下,小偷一晚能夠盜取的最高金額。

方法一

在看完這道題目後,第一反應這是一個動態規劃問題,我們定義process(TreeNode root)返回以root爲根節點的子樹的偷竊最高價值。
是否可以得到一個簡單的遞推關係process(root)=root.val+process(root.left)+process(root.right)呢?根據題意,顯然是不可以的,如果偷竊了root,則不能偷竊root.leftroot.right。這樣,我們必須用一個變量來標識以root爲根節點的子樹偷盜價值中是否包含root的價值,這樣我們的遞歸函數變成了process(TreeNode root,boolean can),其中變量can表示了root節點是否被偷竊。於是得到了以下代碼
在這裏插入圖片描述

class Solution {
    public int rob(TreeNode root) {
        return process(root,true);
    }
	/*返回以root節點爲根節點的子樹的偷竊最大價值*/
    public int process(TreeNode root,boolean can){
        if(root==null)
            return 0;
        int result_1=0;
        int result_2=0;
        if(can==true){//偷竊該節點
            result_1+=root.val;
            result_1+=process(root.left,false);
            result_1+=process(root.right,false); 
        }
        //不偷竊該節點,偷竊左右節點
        result_2+=process(root.left,true);
        result_2+=process(root.right,true);
        return Math.max(result_1,result_2);
    }
}

每一步遞歸的含義是計算以root爲根節點的子樹的偷竊最大價值。
對於遞歸的節點root,如果可以在該節點偷盜,那麼對於以該節點爲根的子樹的偷竊最大值就有兩種情況組成,一種是偷竊root節點,因此就不能偷竊左右子節點;另一種是不偷竊root節點,偷竊其左右節點。比較這兩種情況中偷竊數額最大的一種然後返回給上一層遞歸程序。如果 root節點不能偷竊,那麼就只有一種情況了。
雖然這麼寫最後通過了,但是耗時非常長
在這裏插入圖片描述

方法二

由於方法一耗時很長,我開始思考有沒有可以進行優化的地方。
在處理以root爲根節點的子樹的偷盜價值時,方法一遍歷了兩次,一次can變量賦爲false,一次賦值爲true,其實這兩種情況通過一個遞歸函數就能得到答案。

class Solution {
    public int rob(TreeNode root) {
        int[] res =core(root);
        return Math.max(res[0],res[1]);
    }
    //res[0]爲不包括根節點的最大值,res[1]爲包括根節點的最大值
    public int[] core(TreeNode root){
        if(root==null)
            return new int[]{0,0};
        if(root.left==null&&root.right==null){
            return new int[]{0,root.val};
        }
        int[] l=core(root.left);
        int[] r=core(root.right);
        int[] result=new int[2];
        result[0]=Math.max(l[0],l[1])+Math.max(r[0],r[1]);
        result[1]=root.val+l[0]+r[0];
        return result;
    }
}

通過返回一個數組int[ ],其中int[0]表示不含root價值且以root爲根節點的盜竊最大值,int[1]表示含有root價值且以root爲根節點的盜竊最大值,其思路與方法一其實是類似的,但是大大減少了遞歸的數量,提高了運算速度。
在這裏插入圖片描述

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