3. 二叉树
3.1 前中后序遍历
首先,回顾一下 学习数据结构和算法的框架思维 中说到的二叉树遍历框架:
def traverse(root):
if root is None:
return
# 前序位置
traverse(root.left)
# 中序位置
traverse(root.right)
# 后序位置
先不管所谓前中后序,单看 traverse
函数,你说它在做什么事情?
其实它就是一个能够遍历二叉树所有节点的一个函数,和你遍历数组或者链表本质上没有区别。
二叉树这种结构无非就是二叉链表,由于没办法简单改写成迭代形式,所以一般说二叉树的遍历框架都是指递归的形式。
你也注意到了,只要是递归形式的遍历,都可以有前序位置和后序位置,分别在递归之前和递归之后。
所谓前序位置,就是刚进入一个节点(元素)的时候,后序位置就是即将离开一个节点(元素)的时候,那么进一步,你把代码写在不同位置,代码执行的时机也不同:
- 前序位置的代码在刚刚进入一个二叉树节点的时候执行;
- 后序位置的代码在将要离开一个二叉树节点的时候执行;
- 中序位置的代码在一个二叉树节点左子树都遍历完,即将开始遍历右子树的时候执行。
重点:但这里面大有玄妙,前序位置的代码只能从函数参数中获取父节点传递来的数据,而后序位置的代码不仅可以获取参数数据,还可以获取到子树通过函数返回值传递回来的数据。
二叉树的所有问题,就是让你在前中后序位置注入巧妙的代码逻辑,去达到自己的目的,你只需要单独思考每一个节点应该做什么,其他的不用你管,抛给二叉树遍历框架,递归会在所有节点上做相同的操作。
[104] 二叉树最大深度问题
class Solution(object):
res = 0
depth = 0
def maxDepth(self, root):
"""
:type root: TreeNode
:rtype: int
"""
self.traverse(root)
return self.res
# 定义递归函数
def traverse(self, root):
# global res, depth
if not root:
return
# 前序位置,进入下一层节点,深度加一
self.depth += 1
if not root.left and not root.right:
# 到达叶子节点,更新最大深度
self.res = max(self.res, self.depth)
self.traverse(root.left)
self.traverse(root.right)
# 后序位置,离开该节点时深度减一
self.depth -= 1
3.2 层序遍历
# 输入一棵二叉树的根节点,层序遍历这棵二叉树
def levelTraverse(root: TreeNode):
if not root:
return
# 双端队列
q = deque()
q.append(root)
# 从上到下遍历二叉树的每一层
while q:
sz = len(q)
# 从左到右遍历每一层的每个节点
for i in range(sz):
cur = q.popleft()
# 将下一层节点放入队列
if cur.left:
q.append(cur.left)
if cur.right:
q.append(cur.right)
这里面 while 循环和 for 循环分管从上到下和从左到右的遍历:
3.3 还原二叉树
根据前序和中序遍历结果,还原二叉树:
class Solution:
def deduceTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
# 前序遍历:【根节点,左子树,右子树】
# 中序遍历:【左子树,根节点,右子树】
# 所以前序遍历的第一个元素肯定是根节点,然后找到中序遍历中的根节点,此时中序遍历的左边元素就是左子树元素,右边元素就是右子树元素
# 然后在左右子树中重复这个过程即可
if not preorder or not inorder:
return None
root = TreeNode(preorder[0])
index = inorder.index(preorder[0])
root.left = self.deduceTree(preorder[1:index + 1], inorder[0:index])
root.right = self.deduceTree(preorder[index + 1:], inorder[index + 1:])
return root
# 时间复杂度:查询 index 下标是数组的遍历查询,时间复杂度为o(n), 递归分为左右子树,时间复杂度为log2(n), 此方法时间复杂度为 nlog2(n)