337. 打家劫舍 III

 思路: 考虑每一个节点,小偷有两种选择,偷,或者不偷。

用res[?, ?]存储这两种情况下能偷到的最多的钱。res[0]表示不偷该节点能得到的最多的钱,res[1]表示偷了该节点能得到的最多的钱。

1.如果某个节点是NULL,那么显然,res=[0, 0]
2.如果节点不为空:
  1)不偷此节点的话,其两个子节点偷不偷都可以,对于每个子节点,就看是偷能得到的钱多,还是不偷能拿到的钱多。 

     left表示其左子节点偷或者不偷能得到的最多的钱,right表示其右子节点。那么,res[0] = max(left[0], left[1]) + max(right[0], right[1])

  2)如果偷这个节点,其两个子节点都不能偷。

     用var表示这个节点所拥有的钱,所以,res[1] = var + left[0] + right[0]
由上述的状态转移公式,每个节点的计算都要用到两个子节点的计算结果,所以要用递归来实现!
最后,返回root得到的res中,最大的一个,即max(res[0], res[1])

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None

class Solution:
    def rob(self, root: TreeNode) -> int:
        # 
        def robinteger(root):
            # 如果节点本身就是空的,那无论偷不偷,都拿不到钱
            res = [0, 0]
            if not root: return res
            # res[1]表示节点被偷能拿到的最多的钱
                # 节点被偷的话,其子节点不能被偷
            left = robinteger(root.left)
            right = robinteger(root.right)
            res[1] += root.val + left[0] + right[0]
            # res[0]表示不偷该节点能拿到的最多的钱
                # 不被偷的话,无论其子节点是否被偷都可以
            res[0] += max(left[0], left[1]) + max(right[0], right[1])
            return res
        res = robinteger(root)
        return max(res[0], res[1])

  

作者:corch
链接:https://leetcode-cn.com/problems/house-robber-iii/solution/di-gui-shu-xing-dong-tai-gui-hua-wen-ti-by-corch/
来源:力扣(LeetCode)

原文地址:https://www.cnblogs.com/USTC-ZCC/p/12689593.html