https://leetcode-cn.com/problems/house-robber-iii/
采用后序遍历,主要考察递归和动态规划
参考文献:https://mp.weixin.qq.com/s/BOJ1lHsxbQxUZffXlgglEQ
如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。
相邻层数的父子节点不可全部选择,求树节点的最大之和。
输入: [3,4,5,1,3,null,1]
3
/ \
4 5
/ \ \
1 3 1
输出: 9
解释: 小偷一晚能够盗取的最高金额 = 4 + 5 = 9.
暴力递归
class Solution(object):
def rob(self, root):
"""
:type root: TreeNode
:rtype: int
"""
def dfs(root):
if(not root):
return 0
if(not root.left and not root.right):
return root.val
#偷父节点
val1=root.val
if(root.left):
val1+=dfs(root.left.left)+dfs(root.left.right)
if(root.right):
val1+=dfs(root.right.left)+dfs(root.right.right)
#不偷父节点
val2=dfs(root.left)+dfs(root.right)
return max(val1,val2)
return dfs(root)
时间复杂度:O(n^2) 这个时间复杂度不太标准,也不容易准确化,例如越往下的节点重复计算次数就越多
空间复杂度:O(n) 算上递推系统栈的空间
记忆化递推
class Solution(object):
def rob(self, root):
"""
:type root: TreeNode
:rtype: int
"""
umap={}
def dfs(root):
if(not root):
return 0
if(not root.left and not root.right):
return root.val
if(root in umap): return umap[root]
#偷父节点
val1=root.val
if(root.left):
val1+=dfs(root.left.left)+dfs(root.left.right)
if(root.right):
val1+=dfs(root.right.left)+dfs(root.right.right)
#不偷父节点
val2=dfs(root.left)+dfs(root.right)
umap[root] = max(val1,val2)
return max(val1,val2)
return dfs(root)
umaps用于记录中间结果。
时间复杂度:O(n)
空间复杂度:O(n) 算上递推系统栈的空间
动态规划
用两个值存储当前节点偷和不偷的状态结果。
def rob(self, root):
"""
:type root: TreeNode
:rtype: int
"""
def dp_fun(root):
if(not root):
return [0,0]
left = dp_fun(root.left)
right = dp_fun(root.right)
#偷当前节点
val1=root.val+left[0]+right[0]
#不偷当前节点 如果不偷当前节点,那么左右孩子就可以偷,
#至于到底偷不偷一定是选一个最大的,所以:val2 = max(left[0], left[1]) + max(right[0], right[1]);
val2=max(left[0],left[1])+max(right[1],right[0])
return [val2,val1]
return max(dp_fun(root))
时间复杂度:O(n) 每个节点只遍历了一次
空间复杂度:O(n) 算上递推系统栈的空间