链表和树路径的匹配。
解释: 链表是否存在于树的某条路径中。
Tips:
- 从以
结点为头
的路径,还是左右子路径
?dfs(node) or subpath(left) or subpath(right)
class Solution:
def dfs(self, head: ListNode, rt: TreeNode) -> bool:
if not head:
return True
if not rt:
return False
if rt.val != head.val:
return False
return self.dfs(head.next, rt.left) or self.dfs(head.next, rt.right)
def isSubPath(self, head: ListNode, root: TreeNode) -> bool:
if not root:
return False
return self.dfs(head, root) or self.isSubPath(head, root.left) or self.isSubPath(head, root.right)
2 树的层次遍历(BFS)
tips:
队列
伺候bfs, 节点不为空,队列就加入左右儿子level层
保存着本层的数据
实例:
二叉树:[3,9,20,null,null,15,7],
class Solution(object):
def levelOrder(self, root):
queue = []
queue.append(root)
res = []
while queue:
level = []
for _ in range(len(queue)):
cur = queue.pop(0)
if not cur: #不为null我就加
continue
level.append(cur.val)
queue.append(cur.left)
queue.append(cur.right)
#整完一看。level啥样,如果是空不要了,不然就添加到结果
if level:
res.append(level)
return res
3 树的深度
Tips:
- 递归求解,深度等于左右子节点的深度
最大值+1
- root的深度为0
class Solution:
def Depth(self, root: TreeNode) -> int:
if not root:
return 0
return 1 + max(self.Depth(root.left), self.Depth(root.right))
4 树的最小深度
Tips:
- 和最大深度类似,取
最小
即可 - 但是注意,当
深度为0
, 就不算了,因为深度是叶子节点到根节点的距离!没有叶子自然不算
class Solution:
@functools.lru_cache()
def minDepth(self, root: TreeNode) -> int:
if not root :
return 0
leftDepth = self.minDepth(root.left)
rightDepth = self.minDepth(root.right)
childDepth = min(leftDepth, rightDepth) if leftDepth and rightDepth else leftDepth or rightDepth
return 1 + childDepth
5 判断AVL平衡树
Tips:
- 首先,写出求
深度
的函数 - 然后,判断以每一个结点为root的树,是否是平衡的
abs(left-right)<=1
class Solution:
# 计算以当前节点为根的树深度
def Depth(self, root: TreeNode) -> int:
if not root:
return 0
return 1 + max(self.Depth(root.left), self.Depth(root.right))
def isBalanced(self, root: TreeNode) -> bool:
# 空树是AVL
if not root:
return True
# 若左右子树深度超过1,非AVL
if abs(self.Depth(root.left) - self.Depth(root.right)) > 1:
return False
# 递归执行,当出现不满足AVL性质的子树时,执行短路运算立即返回结果
return self.isBalanced(root.left) and self.isBalanced(root.right)
6 树的最大路径和
Tips:
- 路径的种类有三种,左中右,左中上,右中上
- 如果某个
贡献值<0
? 那就果断不选这个,取0
即可 全局变量
保存目前的最大值,因为不一定经过根节点,最后递归肯定是回归到根节点。
class Solution:
def __init__(self):
self.maxSum = float("-inf")#全局变量记录最大和
def maxPathSum(self, root: TreeNode) -> int:
def maxGain(node):
if not node:
return 0
# 递归计算左右子节点的最大贡献值
# 加了负数,不如不加
leftGain = max(maxGain(node.left), 0)
rightGain = max(maxGain(node.right), 0)
# 左中右路径
priceNewpath = node.val + leftGain + rightGain
# 更新答案
self.maxSum = max(self.maxSum, priceNewpath)
# 返回节点的最大贡献值
return node.val + max(leftGain, rightGain)
maxGain(root)
return self.maxSum
7 收集叶子节点
Tips: 统计height
- res[height]=[] 里面加入height这个高度的节点
class Solution(object):
def findLeaves(self, root):
if not root:
return []
self.res = []
self.delLeaves(root)
return self.res
def delLeaves(self, root):#返回节点树的高度
if root == None:
return -1
leftHeight = self.delLeaves(root.left)
rightHeight = self.delLeaves(root.right)
height = max(leftHeight, rightHeight) + 1
#处理全局变量
if height == len(self.res):
self.res.append([])
self.res[height].append(root.val)
return height
8 n个节点的二叉搜索树种类
tips:
-
卡特兰数
class Solution(object):
'''
卡特兰数
Catalan(n) = C(n,2n)/(n+1) = C(n,2n) - C(n-1, 2n) = Catalan(n-1)*2(2n-1)/n+1
'''
def numTrees(self, n):
"""
:type n: int
:rtype: int
"""
C = 1
for i in range(0, n):
C = C * 2*(2*i+1)/(i+2)
return int(C)
7 n节点的二叉搜索树集合
tips:
- BST有个特点,有顺序!
- 遍历数组,任何一个位置
i
的左边都可以成左子树,右边成为右子树。 -
从左子树集合中选出一棵左子树,从右子树集合中选出一棵右子树,拼接到根节点上
class Solution:
def generateTrees(self, n: int) -> List[TreeNode]:
def generateTrees(start, end):
if start > end:
return [None]
allTrees = []
for i in range(start, end + 1): # 枚举可行根节点
# 获得所有可行的左子树集合
leftTrees = generateTrees(start, i - 1)
# print(leftTrees)
# 获得所有可行的右子树集合
rightTrees = generateTrees(i + 1, end)
# 从左子树集合中选出一棵左子树,从右子树集合中选出一棵右子树,拼接到根节点上
for l in leftTrees:
for r in rightTrees:
currTree = TreeNode(i) #树根节点
currTree.left = l
currTree.right = r
#记录下来
allTrees.append(currTree)
return allTrees
return generateTrees(1, n) if n else []
8 翻转二叉树
tip:
- 每一个结点的左子树和右子树互换
- 然后再换左右子树的子树,recursively
- 返回树,也就是root
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return None
root.left, root.right = root.right, root.left
self.invertTree(root.left)
self.invertTree(root.right)
return root # 这句话就很棒