- 144. Binary Tree Preorder Traversal">144. Binary Tree Preorder Traversal
- 94. Binary Tree Inorder Traversal">94. Binary Tree Inorder Traversal
- 145. Binary Tree Postorder Traversal">145. Binary Tree Postorder Traversal
- 102. Binary Tree Level Order Traversal">102. Binary Tree Level Order Traversal
- 103. Binary Tree Zigzag Level Order Traversal">103. Binary Tree Zigzag Level Order Traversal
- 653. Two Sum IV - Input is a BST">653. Two Sum IV - Input is a BST
- 剑指 Offer 37. 序列化二叉树">剑指 Offer 37. 序列化二叉树
- 剑指 Offer 55 - I. 二叉树的深度">剑指 Offer 55 - I. 二叉树的深度
- 剑指 Offer 55 - II. 平衡二叉树">剑指 Offer 55 - II. 平衡二叉树
- 543. Diameter of Binary Tree">543. Diameter of Binary Tree
- 剑指 Offer 68 - I. 二叉搜索树的最近公共祖先">剑指 Offer 68 - I. 二叉搜索树的最近公共祖先
- 剑指 Offer 68 - II. 二叉树的最近公共祖先">剑指 Offer 68 - II. 二叉树的最近公共祖先
- 剑指 Offer 07. 重建二叉树">剑指 Offer 07. 重建二叉树
- 101. Symmetric Tree">101. Symmetric Tree
- 112. Path Sum">112. Path Sum
- 113. Path Sum II">113. Path Sum II
- 199. Binary Tree Right Side View">199. Binary Tree Right Side View
- 剑指 Offer 54. 二叉搜索树的第k大节点">剑指 Offer 54. 二叉搜索树的第k大节点
- 129. Sum Root to Leaf Numbers">129. Sum Root to Leaf Numbers
- 98. Validate Binary Search Tree">98. Validate Binary Search Tree
- 226. Invert Binary Tree">226. Invert Binary Tree
144. Binary Tree Preorder Traversal
class Solution:def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:res = []def dfs(root):if not root:return # 先序遍历:res.append(root.val) # root(处理当前节点核心逻辑)dfs(root.left) # leftdfs(root.right) # rightdfs(root)return res
- 时间复杂度:
空间复杂度:
class Solution:def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:if not root:return []stack = [root]res = []while stack:node = stack.pop()res.append(node.val)if node.right: # 先right后left,栈FILOstack.append(node.right)if node.left:stack.append(node.left)return res
时间复杂度:
空间复杂度:
class Solution:def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:if not root:return []p = rootstack = []res = []while p or stack:while p: # 一直向左走,边走边加入resres.append(p.val)stack.append(p)p = p.left # 先加入答案数组与栈后,再走向左孩子p = stack.pop().rightreturn res
时间复杂度:
- 空间复杂度:
可采用
Morris遍历将空间复杂度降到,暂不掌握。
94. Binary Tree Inorder Traversal
class Solution:def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:def dfs(root):if not root:returndfs(root.left)res.append(root.val)dfs(root.right)res = []dfs(root)return res
- 时间复杂度:
,每个节点恰好被访问一次
空间复杂度:
,取决于栈的深度,最坏情况下二叉树退化为链表
class Solution:def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:if not root:return []res = []stack = []p = rootwhile p or stack:while p:stack.append(p)p = p.leftnode = stack.pop()res.append(node.val) # 出栈时才将节点值加入resp = node.rightreturn res
时间复杂度:
,每个节点恰好被访问一次
- 空间复杂度:
,取决于栈的深度,最坏情况下二叉树退化为链表
145. Binary Tree Postorder Traversal
class Solution:def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:def dfs(root):if not root:returndfs(root.left)dfs(root.right)res.append(root.val)res = []dfs(root)return res
- 时间复杂度:
- 空间复杂度:
镜像先序遍历,再翻转输出。没有模拟真实的栈操作,是不太可取的做法。
class Solution:def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:if not root:return []res = []stack = [root]while stack:node = stack.pop()res.append(node.val)if node.left:stack.append(node.left)if node.right:stack.append(node.right)return res[::-1]
class Solution:def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:if not root:return []res = []stack = []p = rootwhile p or stack:while p:res.append(p.val)stack.append(p)p = p.rightp = stack.pop().leftreturn res[::-1]
- 时间复杂度:
- 空间复杂度:
利用栈的特性,增加一次入栈-出栈过程,通过flag位的设计使得两次出入栈的节点才能加入答案数组,以实现迭代版本的后序遍历。
class Solution:def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:if not root:return []res = []stack = [(0, root)]while stack:flag, node = stack.pop()if flag == 1: # 第二次遍历,加入resres.append(node.val)else: # 首次遍历,falg=1入栈,并将右-左孩子以flag=0入栈stack.append((1, node))if node.right:stack.append((0, node.right))if node.left:stack.append((0, node.left))return res
- 时间复杂度:
- 空间复杂度:
102. Binary Tree Level Order Traversal
from collections import dequeclass Solution:def levelOrder(self, root: TreeNode) -> List[List[int]]:if not root:return []res = []queue = deque([root])while queue:layer, num_layer = [], len(queue)for _ in range(num_layer):node = queue.popleft()layer.append(node.val)if node.left:queue.append(node.left)if node.right:queue.append(node.right)res.append(layer)return res
- 时间复杂度:
- 空间复杂度:
103. Binary Tree Zigzag Level Order Traversal
653. Two Sum IV - Input is a BST
Approach I
利用set记录,递归dfs实现,但没用到BST的特性。
同样可以使用bfs+queue实现,不再赘述。
class Solution:def __init__(self):self.dic = set()def findTarget(self, root: Optional[TreeNode], k: int) -> bool:if not root:return Falseif k - root.val in self.dic:return Trueself.dic.add(root.val)return self.findTarget(root.left, k) or self.findTarget(root.right, k)
- 时间复杂度:
- 空间复杂度:
Approach II
再说吧
Approach II
再说啊
剑指 Offer 37. 序列化二叉树
class Codec:def serialize(self, root):if not root:return ''data = []queue = deque([root])while queue:node = queue.popleft()if node:data.append(str(node.val))queue.append(node.left)queue.append(node.right)else:data.append('null')return ','.join(data)def deserialize(self, data):if data == '':returndata = data.split(',')root = TreeNode(int(data[0]))index = 1queue = deque([root])while queue:node = queue.popleft()if data[index] != 'null':node.left = TreeNode(int(data[index]))queue.append(node.left)index += 1if data[index] != 'null':node.right = TreeNode(int(data[index]))queue.append(node.right)index += 1return root
- 时间复杂度:
- 空间复杂度:
class Codec:def serialize(self, root):if not root:return 'null'return str(root.val) + ',' + self.serialize(root.left) \+ ',' + self.serialize(root.right)def deserialize(self, data):def dfs(vals):if (val := vals.popleft()) == 'null':returnnode = TreeNode(int(val))node.left = dfs(vals)node.right = dfs(vals)return nodevals = deque(data.split(','))return dfs(vals)
剑指 Offer 55 - I. 二叉树的深度
class Solution:def maxDepth(self, root: TreeNode) -> int:return 1 + max(self.maxDepth(root.left), self.maxDepth(root.right)) \if root else 0
- 时间复杂度:
空间复杂度:
,取决于递归调用栈深度,最差情况退化为链表
class Solution:def maxDepth(self, root: TreeNode) -> int:if not root:return 0queue = deque([root])depth = 0while queue:depth += 1num_layer = len(queue)for _ in range(num_layer):node = queue.popleft()if node.left:queue.append(node.left)if node.right:queue.append(node.right)return depth
时间复杂度:
- 空间复杂度:
,队列中最多存储
个节点
剑指 Offer 55 - II. 平衡二叉树
Approach I** 先序遍历 + 判断深度 (自顶向下)**
class Solution:def isBalanced(self, root: TreeNode) -> bool:if not root:return Truereturn abs(self.count_height(root.left) - self.count_height(root.right)) <= 1 \and self.isBalanced(root.left) and self.isBalanced(root.right)def count_height(self, root) -> int:return 1 + max(self.count_height(root.left), self.count_height(root.right)) \if root else 0
- 时间复杂度:
- 空间复杂度:
Approach I** 后序遍历 + 剪枝 (自底向上)**
class Solution:def isBalanced(self, root: TreeNode) -> bool:def postorder_dfs(root): # 若平衡,返回深度if not root: # 若不平衡,返回-1(剪枝)return 0if (left := postorder_dfs(root.left)) == -1:return -1if (right := postorder_dfs(root.right)) == -1:return -1return 1 + max(left, right) if abs(left - right) <= 1 else -1return postorder_dfs(root) != -1
- 时间复杂度:
- 空间复杂度:
543. Diameter of Binary Tree
**最大直径**不一定会经过root!故需要遍历所有节点判断。
- 使用类变量来记录&更新结果
同
**平衡二叉树**的判断,使用后序遍历(自底向上)来减少复杂度若使用先序遍历,会造成大量重复计算
class Solution: def diameterOfBinaryTree(self, root: TreeNode) -> int: self.diameter = 0 def count_height(root): if not root: return 0 L = count_height(root.left) R = count_height(root.right) self.diameter = max(self.diameter, L + R) return 1 + max(L, R) count_height(root) return self.diameter
- 时间复杂度:
- 空间复杂度:
剑指 Offer 68 - I. 二叉搜索树的最近公共祖先
对于**二叉搜索树**,恒有
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if p.val < root.val and q.val < root.val: # p, q位于root左子树
return self.lowestCommonAncestor(root.left, p, q)
if p.val > root.val and q.val > root.val: # p, q位于root右子树
return self.lowestCommonAncestor(root.right, p, q)
return root # p, q位于root两侧 || p或q就是root
- 时间复杂度:
- 空间复杂度:
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if p.val > q.val: # 保证p.val < q.val
return self.lowestCommonAncestor(root, q, p)
while root:
if q.val < root.val: # p, q位于root左子树
root = root.left
elif root.val < p.val: # p, q位于root右子树
root = root.right
else: # p, q位于root两侧 || p或q就是root
return root
- 时间复杂度:
- 空间复杂度:
剑指 Offer 68 - II. 二叉树的最近公共祖先
class Solution:
# 返回以root为根的二叉树中,p, q节点的最近公共祖先
def lowestCommonAncestor(self, root: TreeNode, p: TreeNode, q: TreeNode) -> TreeNode:
if not root or root == p or root == q: # 若不成立,LCA必然不是root
return root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
if not left and not right: # root的左右子树都分别不'同时包含p,q'
return
if left and right: # p,q在root的异侧
return root
return left if left else right # if left:
# 1. p,q其中一个在root的左子树中
# 2. p,q都在root的左子树中
- 时间复杂度:
- 空间复杂度:
剑指 Offer 07. 重建二叉树
使用dict来存储中序遍历的到
的映射,故只适用于无重复节点值的二叉树。
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
'''
idx_pre: 前序遍历根节点的索引
low: 中序遍历左边界
high: 中序遍历右边界
'''
def build(idx_pre, low, high) -> TreeNode:
if low > high:
return
val_root = preorder[idx_pre]
idx_in = dic[val_root]
root = TreeNode(val_root)
root.left = build(idx_pre + 1, low, idx_in - 1)
root.right = build(idx_pre + 1 + (idx_in - low), idx_in + 1, high)
return root
dic = dict()
for index, num in enumerate(inorder):
dic[num] = index
return build(0, 0, len(inorder) - 1)
- 时间复杂度:
- 空间复杂度:
101. Symmetric Tree
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
# 判断L,R子树是否对称
def dfs(L, R) -> bool:
if not L and not R: # L,R都为空
return True
if not L or not R: # L,R二者之一为空 || 存储的'val'不同
return False
# 递归比较
return dfs(L.left, R.right) and dfs(L.right, R.left)
return dfs(root.left, root.right)
- 时间复杂度:
- 空间复杂度:
class Solution:
def isSymmetric(self, root: Optional[TreeNode]) -> bool:
queue = collections.deque([root.left, root.right])
while queue:
L, R = queue.popleft(), queue.popleft()
if not L and not R:
continue
if not L or not R or L.val != R.val:
return False
queue += [L.left, R.right, L.right, R.left]
return True
- 时间复杂度:
- 空间复杂度:
112. Path Sum
板子题
root == None,恒为- 记得判断当前
root是否为叶子节点:if not root.left and not root.rightclass Solution: # 遍历到root节点(还未考虑root.val),剩余需要填充的值是target def hasPathSum(self, root: Optional[TreeNode], target: int) -> bool: if not root: # 空节点 return False if not root.left and not root.right: # 叶子节点 return target == root.val return self.hasPathSum(root.left, target - root.val) or \ self.hasPathSum(root.right, target - root.val)
- 时间复杂度:
- 空间复杂度:
class Solution:
def hasPathSum(self, root: Optional[TreeNode], target: int) -> bool:
if not root:
return False
queue = collections.deque([(root, root.val)])
while queue:
node, path_sum = queue.popleft()
if not node.left and not node.right:
if path_sum == target:
return True
if node.left:
queue.append((node.left, path_sum + node.left.val))
if node.right:
queue.append((node.right, path_sum + node.right.val))
return False
- 时间复杂度:
- 空间复杂度:
113. Path Sum II
class Solution:
def pathSum(self, root: Optional[TreeNode], target: int) -> List[List[int]]:
def dfs(root, remain, path):
if not root:
return
if not root.left and not root.right:
if remain == root.val:
res.append(path + [root.val])
return
dfs(root.left, remain - root.val, path + [root.val])
dfs(root.right, remain - root.val, path + [root.val])
res = []
dfs(root, target, [])
return res
199. Binary Tree Right Side View
遍历顺序为,额外使用变量
**depth**来记录树的深度,可以构造出右视图的访问顺序。
class Solution:
def rightSideView(self, root: TreeNode) -> List[int]:
def dfs(root, depth):
if not root:
return
if depth == len(res):
res.append(root.val)
dfs(root.right, depth+1)
dfs(root.left, depth+1)
res = []
dfs(root, 0)
return res
- 时间复杂度:
- 空间复杂度:
利用队列进行广度优先搜索,只加入每一层的最后一个节点。
class Solution:
def rightSideView(self, root: TreeNode) -> List[int]:
if not root:
return []
res = []
depth = 0
queue = collections.deque([root])
while queue:
num_layer = len(queue)
for _ in range(num_layer):
node = queue.popleft()
if depth == len(res):
res.append(node.val)
if node.right:
queue.append(node.right)
if node.left:
queue.append(node.left)
depth += 1
return res
- 时间复杂度:
- 空间复杂度:
剑指 Offer 54. 二叉搜索树的第k大节点
使用类变量self.k和self.res来维护元素rank和节点值,逆向中序遍历,把逻辑处理全部写在对当前节点的操作上,故而简化了dfs()的参数。
class Solution:
def kthLargest(self, root: TreeNode, k: int) -> int:
def dfs(root):
if not root:
return
dfs(root.right)
###
self.k -= 1
if self.k == 0:
self.res = root.val
return # 剪枝
###
dfs(root.left)
self.k = k
dfs(root)
return self.res
- 时间复杂度:
- 空间复杂度:
129. Sum Root to Leaf Numbers

class Solution:
def sumNumbers(self, root: TreeNode) -> int:
def dfs(root, prev_total):
if not root:
return 0
total = prev_total * 10 + root.val
if not root.left and not root.right:
return total
else:
return dfs(root.left, total) + dfs(root.right, total)
return dfs(root, 0)
class Solution:
def sumNumbers(self, root: TreeNode) -> int:
res = 0
queue = deque([(root, 0)])
while queue:
node, pre_total = queue.popleft()
total = pre_total * 10 + node.val
if not node.left and not node.right:
res += total
if node.left:
queue.append((node.left, total))
if node.right:
queue.append((node.right, total))
return res
- 时间复杂度:
- 空间复杂度:
98. Validate Binary Search Tree
226. Invert Binary Tree
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return
root.left, root.right = self.invertTree(root.right), self.invertTree(root.left)
return root
class Solution:
def invertTree(self, root: TreeNode) -> TreeNode:
if not root:
return
queue = collections.deque([root])
while queue:
node = queue.popleft()
node.left, node.right = node.right, node.left
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return root
- 时间复杂度:
- 空间复杂度:
