1. 程式人生 > >Leetcode 337:打家劫舍 III(最詳細的解法!!!)

Leetcode 337:打家劫舍 III(最詳細的解法!!!)

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

計算在不觸動警報的情況下,小偷一晚能夠盜取的最高金額。

示例 1:

輸入: [3,2,3,null,3,null,1]

     3-
    / \
   2   3
    \   \ 
     3-  1-

輸出: 7 
解釋: 小偷一晚能夠盜取的最高金額 = 3 + 3 + 1 = 7.

示例 2:

輸入: [3,4,5,1,3,null,1]

     3
    / \
   4-  5-
  / \   \ 
 1   3   1

輸出: 9
解釋: 小偷一晚能夠盜取的最高金額 = 4 + 5 = 9.

解題思路

思路和之前一樣,我們遍歷整棵二分搜尋樹,對於每個節點,我們都需要判斷這個節點的值我們需不需要取。例如

     3<-
    / \
   2   3
    \   \ 
     3   1

如果我們取3,那麼3.left and 3.right我們都不能取了;如果我們不取,那麼最大值來自於左右孩子的和,也就是3.left+3.right,但是對於左右孩子來說又涉及到了上面的問題,我們是取還是不取呢?這樣迴圈遞推下去,知道節點為null

,我們直接返回0即可。那麼我們對於每個節點,都要設計一個結構來描述取和不取這樣的操作,使用list即可,list[0]表示取,而list[1]表示不取。

我們定義root的左右孩子為l & r,左孩子l的左右孩子為ll & lr,右孩子r的左右孩子為rl & rr。那麼我們可以寫出這樣的方程

result = max(root.val + f(ll) + f(lr) + f(rl) + f(rr), f(l) + f(r))
f = max(rob, norob)

我們可以很快速的寫出下面程式碼

class Solution:
    def rob(self, root)
: """ :type root: TreeNode :rtype: int """ check = self._rob(root) return max(check[0], check[1]) def _rob(self, root): if not root: return [0, 0] l, r = self._rob(root.left), self._rob(root.right) return l[1] + r[1] + root.val, max(l) + max(r)

但是這個程式碼依舊有優化的空間,我們可以通過記憶化搜尋的方法繼續優化這個程式碼。但是我們怎麼記憶各個節點的訪問情況呢?之前的問題都是list,所以我們可以通過index來建立搜尋列表。對於這個問題我們有一個小技巧就是通過l & r表示左右,例如lll表示左子樹的左子樹的左子樹。

class Solution:
    def rob(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        mem = dict()
        check = self._rob(root, "", mem)
        return max(check[0], check[1])

    def _rob(self, root, path, mem):
        if not root:
            return [0, 0]

        if path in mem:
            return mem[path]

        l, r = self._rob(root.left, path + 'l', mem), self._rob(root.right, path + 'r', mem)
        mem[path] = l[1] + r[1] + root.val, max(l) + max(r)
        return mem[path]

我們怎麼通過迭代解決這個問題呢?實際上這個問題變成了我們怎麼去遍歷一顆二叉樹,怎麼做呢?

我這裡通過前序遍歷解決這個問題

class Solution:
    def rob(self, root):
        """
        :type root: TreeNode
        :rtype: int
        """
        stack = [(0, root)]
        result = {None: (0, 0)}
        while stack:
            rob, node = stack.pop()
            if not node:
                continue
                
            if not rob:
                stack.extend([(1, node), (0, node.right), (0, node.left)])
            else:
                result[node] = (result[node.left][1] + result[node.right][1] + node.val,\
                               max(result[node.left]) + max(result[node.right]))
        return max(result[root])

如有問題,希望大家指出!!!