打家劫舍 III
记忆化递归,后续遍历,单个状态转移
一开始想不出什么好的方法,就用了dfs+剪枝的方法,采用后续遍历的方式,每个节点返回这棵子树能获得的最大金额。
最大金额分两种情况,当前节点偷和当前节点不偷
# 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:
dict1 = {}
def _dfs(root):
if root == None:
return 0
value1 = 0
value2 = 0
for item in (root.left, root.right):# 遍历两个孩子节点
if not item :
dict1[item] = 0
continue
if item in dict1.keys():
tempValue = dict1[item]
else: tempValue = _dfs(item); dict1[item] = tempValue
value1 += tempValue
for child in (item.left, item.right):# 遍历4个孙子节点
tempValue = _dfs(child)
if child in dict1.keys():
tempValue = dict1[child]
else: tempValue = _dfs(child); dict1[child] = tempValue
value2 += tempValue
maxValue = max(value1, value2 + root.val)
dict1[root] = maxValue
return maxValue
return _dfs(root)
上面的记忆化递归过于难看,用字典来保存状态只需要在递归函数的首尾即可,下面的更清晰
# 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:
dict1 = {}
def _dfs(root):
if root == None:
return 0
if root in dict1.keys(): # 判断字典中是否已经包含
return dict1[root] # 直接返回对应的状态
value1 = 0
value2 = 0
for item in (root.left, root.right):# 遍历两个孩子节点
if not item :
dict1[item] = 0
continue
tempValue = _dfs(item);
value1 += tempValue
for child in (item.left, item.right): # 遍历4个孙子节点
tempValue = _dfs(child)
value2 += tempValue
maxValue = max(value1, value2 + root.val)
dict1[root] = maxValue # 记忆当前节点的状态
return maxValue
return _dfs(root)
后续遍历,dfs, 两个状态转移,字典,lambda
这里为了处理None节点与字典对None节点的初始化,使用defaultdict(lambda : 0) , 对于新增键值,字典的返回结果为0, defaultdict()只能传入不带参数的函数,或者None值。这里使用了lambda表达式。
# 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:
dict0 = defaultdict(lambda : 0)
dict1 = defaultdict(lambda : 0)
def _dfs(root):
if not root:
return 0
_dfs(root.left)
_dfs(root.right)
dict0[root] = max(dict0[root.left], dict1[root.left]) + max(dict0[root.right], dict1[root.right])
dict1[root] = dict0[root.left] + dict0[root.right] + root.val
_dfs(root)
return max(dict0[root], dict1[root])
对于上面的代码可以简化一下
因为涉及到的状态只和孩子节点有关,状态可以通过孩子节点返回。就省了字典的开销了。
# 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 _dfs(root):
if not root:
return (0,0)
lvalue = _dfs(root.left)
rvalue = _dfs(root.right)
noselected = max(lvalue[0], lvalue[1]) + max(rvalue[0], rvalue[1])
selected = lvalue[0]+rvalue[0] + root.val
return (noselected, selected)
res = _dfs(root)
return max(res[0], res[1])