难度:中等
题目描述:
思路总结:
刚开始想到了二叉树的层次遍历,其实这题可以用层次遍历+DP解决。然后看答案树形DP,初始解法一+后续两种优化。
题解一:(超时)
其实还是递归层数的问题,加个lru_cache()装饰器就好了。
# 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:
#思路:爷爷+孙子 vs. 儿子
if not root:return 0
money = root.val
if root.left:
money += self.rob(root.left.left) + self.rob(root.left.right)
if root.right:
money += self.rob(root.right.left) + self.rob(root.right.right)
return max(money, self.rob(root.left)+self.rob(root.right))
题解一结果:
我佛,人家Java都不超时。
加了lru_cache()之后的结果:
题解二:
爷爷+孙子和爸爸,两下计算下来,必然是有一大部分是重叠计算,因此我们可以用记忆法进行优化,搞一个dict存储每个结点的最大偷钱数。
note:这里不能用lru_cache()进行优化了,因为函数中有不能hashable的参数。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
import functools
class Solution:
# @functools.lru_cache(None)
def rob(self, root: TreeNode) -> int:
#思路:爷爷+孙子 vs. 儿子
memo = {}
def robWhat(root, memo):
if not root:return 0
if root in memo.keys():
return memo[root]
money = root.val
if root.left:
money += robWhat(root.left.left, memo) + robWhat(root.left.right, memo)
if root.right:
money += robWhat(root.right.left, memo) + robWhat(root.right.right, memo)
res = max(money, robWhat(root.left, memo)+robWhat(root.right, memo))
memo[root] = res
return res
return robWhat(root, memo)
题解二结果:
看来上面的判断还是有误,使用记忆法以后我们可以得到不错的结果。由此可见,上面原始代码的问题是递归次数过多导致的导致运算过慢。(而不是层级过多)
题解三:
我们可以转变一个思路。对于每个节点来说,就是偷或者不偷,如果偷,存左右子节点选择不偷加当前结点值;如果不偷,存左右子节点选择偷最大值相加。
实现其实也很简单。就是每次迭代时迭代计算左右孩子的(不偷,偷)的最大值,然后返回当前结点的(不偷,偷)的最大值,每次返回元组。(不偷:选左子节点偷/不偷的最大值,右同理;偷:选左右子节点不偷值+当前结点值)
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
import functools
class Solution:
def rob(self, root: TreeNode) -> int:
def robWhat(node):
if not node:return (0, 0)
left = robWhat(node.left)
right = robWhat(node.right)
return (max(left[0], left[1])+max(right[0], right[1]), left[0]+right[0]+node.val)
return max(robWhat(root))