看到关于二叉树的问题,首先要想到关于二叉树的一些常见遍历方式,
对于二叉树的遍历有
前序遍历
中序遍历
后续遍历
深度优先搜索(DFS)
宽度优先搜索(BFS)
除了上面介绍的5种以外,还有Morris(莫里斯)的前中后3种遍历方式,总共也就这8种。所以只要遇到二叉树相关的算法题,首先想到的就是上面的几种遍历方式,然后再稍加修改,基本上也就这个套路。
这题让求的就是让把二叉树中每行都串联起来,对于这道题来说最适合的就是BFS。也就是一行一行的遍历,遍历的时候顺便把他们给串起来,如下图所示
def _build_tree_string(root, curr_index, include_index, delimiter):
if root is None: return [], 0, 0, 0
line1, line2 = [], []
if include_index:
node_repr = "{}{}{}".format(curr_index, delimiter, root.val)
else:
node_repr = str(root.val)
new_root_width = gap_size = len(node_repr)
# Get the left and right sub-boxes, their widths, and root repr positions
l_box, l_box_width, l_root_start, l_root_end = _build_tree_string(
root.left, 2 * curr_index + 1, include_index, delimiter)
r_box, r_box_width, r_root_start, r_root_end = _build_tree_string(
root.right, 2 * curr_index + 2, include_index, delimiter)
# Draw the branch connecting the current root node to the left sub-box
# Pad the line with whitespaces where necessary
if l_box_width > 0:
l_root = (l_root_start + l_root_end) // 2 + 1
line1.append(" " * (l_root + 1))
line1.append("_" * (l_box_width - l_root))
line2.append(" " * l_root + "/")
line2.append(" " * (l_box_width - l_root))
new_root_start = l_box_width + 1
gap_size += 1
else:
new_root_start = 0
# Draw the representation of the current root node
line1.append(node_repr)
line2.append(" " * new_root_width)
# Draw the branch connecting the current root node to the right sub-box
# Pad the line with whitespaces where necessary
if r_box_width > 0:
r_root = (r_root_start + r_root_end) // 2
line1.append("_" * r_root)
line1.append(" " * (r_box_width - r_root + 1))
line2.append(" " * r_root + "\\")
line2.append(" " * (r_box_width - r_root))
gap_size += 1
new_root_end = new_root_start + new_root_width - 1
# Combine the left and right sub-boxes with the branches drawn above
gap = " " * gap_size
new_box = ["".join(line1), "".join(line2)]
for i in range(max(len(l_box), len(r_box))):
l_line = l_box[i] if i < len(l_box) else " " * l_box_width
r_line = r_box[i] if i < len(r_box) else " " * r_box_width
new_box.append(l_line + gap + r_line)
return new_box, len(new_box[0]), new_root_start, new_root_end
class TreeNode:
def __init__(self, val=0, left=None, right=None):
self.val = val
self.left = left
self.right = right
def __str__(self) -> str:
lines = _build_tree_string(self, 0, False, "-")[0]
return "\n" + "\n".join((line.rstrip() for line in lines))
from typing import List, Optional, Tuple
class BTree():
def __init__(self, root=None):
self.root = root
self.depth = 0
def add(self, item):
node = TreeNode(item)
if self.root is None:
self.root = node
return
else:
queue = []
queue.append(self.root)
while queue:
cur_node = queue.pop(0)
if cur_node.left is None:
cur_node.left = node
return
elif cur_node.right is None:
cur_node.right = node
return
else:
queue.append(cur_node.left)
queue.append(cur_node.right)
# 先访问根节点,然后遍历左子树,最后遍历右子树。
def preorderTraversal(self, root):
if not root: return []
res = []
# recursion
def preorder(root):
if not root: return
res.append(root.val)
preorder(root.left)
preorder(root.right)
preorder(root)
# Iteration1
# stack = []
# cur = root
# while stack or cur:
# while cur:
# res.append(cur.val)
# stack.append(cur)
# cur = cur.left
# cur = stack.pop()
# cur = cur.right
# # Iteration2
# stack = [root]
# while(stack):
# cur = stack.pop()
# res.append(cur.val)
# if cur.right:
# stack.append(cur.right)
# if cur.left:
# stack.append(cur.left)
return res
# 先遍历左子树,然后访问根节点,然后遍历右子树。
def inorderTraversal(self, root):
if not root: return []
res = []
# recursion
def inorder(root):
if not root: return
inorder(root.left)
res.append(root.val)
inorder(root.right)
inorder(root)
# Iteration1
# stack = []
# cur = root
# while stack or cur:
# while cur:
# stack.append(cur)
# cur = cur.left
# cur = stack.pop()
# res.append(cur.val)
# cur = cur.right
# # Iteration2
# stack = [root]
# while(stack):
# cur = stack.pop()
# res.append(cur.val)
# if cur.right:
# stack.append(cur.right)
# if cur.left:
# stack.append(cur.left)
return res
# 先遍历左子树,然后遍历右子树,最后访问树的根节点。
def poseorderTraversal(self, root):
if not root: return []
res = []
# recursion
def poseorder(root):
if not root: return
poseorder(root.left)
poseorder(root.right)
res.append(root.val)
poseorder(root)
# Iteration1
# stack = []
# cur = root
# while stack or cur:
# while cur:
# res.append(cur.val)
# stack.append(cur)
# cur = cur.right
# cur = stack.pop()
# cur = cur.left
# res = res[::-1]
# # Iteration2
# stack = [root]
# while(stack):
# cur = stack.pop()
# res.append(cur.val)
# if cur.left: stack.append(cur.left)
# if cur.right: stack.append(cur.right)
# res = res[::-1]
return res
# BFS
def levelorderTraversal(self, root):
if not root:
return []
queue, res = [root], []
while (queue):
# cur = queue.pop(0)
# res.append(cur.val)
# if cur.left: queue.append(cur.left)
# if cur.right: queue.append(cur.right)
# 显示层数
res.append([node.val for node in queue])
res.append(['*'])
size = len(queue)
for i in range(size):
cur = queue.pop(0)
if cur.left: queue.append(cur.left)
if cur.right: queue.append(cur.right)
return res
def maximum_depth(self, root):
if not root: return 0
def max_depth(cur, depth):
if not cur: return
if (not cur.left and not cur.right):
if self.depth < depth:
self.depth = depth
max_depth(cur.left, depth + 1)
max_depth(cur.right, depth + 1)
max_depth(root, 1)
return self.depth
def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode:
"""
:param preorder: [3,9,20,15,77] 根 左 右
:param inorder: [9,3,15,20,7] 左 根 右
:param postorder: [9,15,7,20,3] 左 右 根
:return:
"""
def build(in_left, in_right):
if in_left > in_right: return None
# 选择 pre_idx 位置的元素作为当前子树根节点
val = preorder.pop(0)
root = TreeNode(val)
# 根据 root 所在位置分成左右两棵子树
index = idx_map[val]
# 构造左子树
root.left = build(in_left, index - 1)
# 构造右子树
root.right = build(index + 1, in_right)
return root
# 建立(元素,下标)键值对的哈希表
idx_map = {val: idx for idx, val in enumerate(inorder)}
return build(0, len(inorder) - 1)
tree0 = TreeNode(2)
tree0.left = TreeNode(1)
tree0.left.left = TreeNode(0)
tree0.left.right = TreeNode(2)
tree0.right = TreeNode(3)
tree0.right.left = TreeNode(2)
tree0.right.right = TreeNode(4)
BT = BTree()
tree0 = BT.buildTree([2, 1, 0, 4, 3, -1, 5], [0, 1, 4, 2, -1, 3, 5])
print(tree0)
result0 = BT.preorderTraversal(tree0)
print("前序遍历(根->左->右)", result0)
result1 = BT.inorderTraversal(tree0)
print("中序遍历(左->根->右)", result1)
result2 = BT.poseorderTraversal(tree0)
print("后序遍历(左->右->根)", result2)
result2 = BT.levelorderTraversal(tree0)
print("层序遍历 ", result2)
result3 = BT.maximum_depth(tree0)
print(result3)
exit()