1. 程式人生 > 資訊 >京東 6.6 元:熊貓精釀陳皮小麥啤酒 2.5 元 / 罐探底

京東 6.6 元:熊貓精釀陳皮小麥啤酒 2.5 元 / 罐探底

337. 打家劫舍 III

題目連結:337. 打家劫舍 III(中等)

小偷又發現了一個新的可行竊的地區。這個地區只有一個入口,我們稱之為 root

除了 root 之外,每棟房子有且只有一個“父“房子與之相連。一番偵察之後,聰明的小偷意識到“這個地方的所有房屋的排列類似於一棵二叉樹”。 如果 兩個直接相連的房子在同一天晚上被打劫 ,房屋將自動報警。

給定二叉樹的 root 。返回 *在不觸動警報的情況下 ,小偷能夠盜取的最高金額* 。

示例 1:

輸入: root = [3,2,3,null,3,null,1]
輸出: 7
解釋: 小偷一晚能夠盜取的最高金額 3 + 3 + 1 = 7

示例 2:

輸入: root = [3,4,5,1,3,null,1]
輸出: 9
解釋: 小偷一晚能夠盜取的最高金額 4 + 5 = 9

提示:

  • 樹的節點數在 [1, 104] 範圍內

  • 0 <= Node.val <= 104

解題思路

根據題目的意思,每個節點有偷與不偷兩種狀態。

  • 偷當前節點,那左右孩子節點就不能偷了。

  • 不偷當前節點,那取左右孩子節點能獲得的最大金額(注意:這與兩個孩子節點偷或不偷沒有關係)。

因為是樹形結構,採用遞迴的方法,有遞迴三部曲。另外還有動態規劃五部曲。

詳細分析在程式碼的註釋中。

C++

struct TreeNode {
    
int val; TreeNode* left; TreeNode* right; TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}; }; ​ // 此處我們需要對樹進行一個**後序遍歷**,由葉子節點開始考慮,直至根節點。 class Solution { public: int rob(TreeNode* root) { vector<int> result = robTree(root); return max(result[0], result[1
]); } // 遞迴三部曲 1.確定遞迴函式的引數和返回值 // 函式引數就是當前的節點 // 返回dp陣列,該陣列由兩項構成,dp[0]表示不偷當前節點能夠得到的最大金額,dp[1]表示偷當前節點能夠得到的最大金額 vector<int> robTree(TreeNode* node) { // 遞迴三部曲 2.確定終止條件 // 動規五部曲 3.dp陣列的初始化 // 當前節點為空,無論偷與不偷能得到的最大金額都是0 if (node == nullptr) return {0, 0}; // 遞迴三部曲 3.確定單層遞迴的邏輯 // 動規五部曲 4.遍歷順序:後序遍歷 vector<int> left = robTree(node->left); vector<int> right = robTree(node->right); // 動規五部曲 1.dp陣列的含義,該陣列由兩項構成,dp[0]表示不偷當前節點能夠得到的最大金額,dp[1]表示偷當前節點能夠得到的最大金額 vector<int> dp(2); // 動規五部曲 2.遞推公式 // 當前節點選擇不偷:當前節點能偷到的最大錢數 = 左孩子能偷到的最大金額 + 右孩子能偷到的最大金額 dp[0] = max(left[0], left[1]) + max(right[0], right[1]); //當前節點選擇偷:當前節點能偷到的最大錢數 = 左孩子選擇自己不偷時能得到的錢 + 右孩子選擇不偷時能得到的錢 + 當前節點的錢數 dp[1] = left[0] + right[0] + node->val; return dp; } };

JavaScript

/**
 * @param {number} val
 * @param {TreeNode} left
 * @param {TreeNode} right
 */
function TreeNode(val, left, right) {
    this.val = (val === undefined ? 0 : val)
    this.left = (left === undefined ? null : left)
    this.right = (right === undefined ? null : right)
}
​
/**
 * @param {TreeNode} root
 * @return {number}
 */
var rob = function(root) {
    const robTree = node => {
        if (node === null) return [0, 0];
        let leftVal = robTree(node.left);
        let rightVal = robTree(node.right);
        let dp0 = Math.max(leftVal[0], leftVal[1]) + Math.max(rightVal[0], rightVal[1]);
        let dp1 = leftVal[0] + rightVal[0] + node.val;
        return [dp0, dp1];
    }
    let result = robTree(root);
    return Math.max(...result);
};
  • 時間複雜度:O(n),每個節點只遍歷了一次

  • 空間複雜度:O(log n),算上遞推系統棧的空間