1. 程式人生 > >337. House Robber III的C++解法(遞迴+dp)

337. House Robber III的C++解法(遞迴+dp)

題目描述:https://leetcode.com/problems/house-robber-iii/

一開始被描述中的例子誤導了,覺得應該只能打劫間隔的一層,所以寫了一個層次遍歷,計算每一層的和再決定怎麼打劫。後來發現是不對的,因為可以打劫左子樹而不打劫右子樹,如樹[2,7,1,null,4,null,8]

對於二叉樹中的某一個節點i,它也有偷與不偷這兩個選項,若偷,則兩個子節點不能偷;否則,兩個子節點可以偷。與I、II不同的是,I、II中對當前的房屋i,偷與不偷僅需把其中的較大者保留下來進行,因為後續的結果均是建立在前者為最優解的基礎上進行的,而且DP[i] = max{DP[i-1],DP[i-2]+A[i]}一定能保證不發生衝突;但是對於二叉樹,當前節點i並不能那麼方便的找到其子節點的子節點的最優解,因此並不能同I、II那樣僅記錄最優解。對於二叉樹的節點而言,其最容易訪問到的就是它的兩個子節點。因此,可以建立一個大小為2的一維陣列DP,其中DP[0]用來記錄偷當前節點所能獲利值,DP[1]用來記錄不偷當前的值所能獲利的值。使用遞迴的方法求解。

class Solution {
public:
    int rob(TreeNode* root) {
        vector<int> res=helper(root);
        return max(res[0],res[1]);
        
    }
    vector<int> helper(TreeNode* root){
        vector<int> res={0,0};
        if (root==NULL) return res;
        //得到打劫或者不打劫左子樹的結果
        vector<int> left=helper(root->left);
        //得到打劫或者不打劫右子樹的結果
        vector<int> right=helper(root->right);
        //打劫根節點則不打劫左右子樹
        res[0]=left[1]+right[1]+root->val;
        //否則計算左右子樹可以打劫時的最大情況
        res[1]=max(left[0],left[1])+max(right[1],right[0]);
        return res;
        
    }
};