题目介绍
题目:94. 二叉树的中序遍历
描述:给定一个二叉树,返回它的中序遍历。
输入:
[1,null,2,3]
1
\
2
/
3
输出:[1,3,2]
进阶: 递归算法很简单,你可以通过迭代算法完成吗?
题目理解 & 解题思路
题目理解:最基本的遍历之一。
中序遍历:先中序遍历左子树,再访问根节点,再中序遍历右子树
解题思路:可以使用递归和迭代算法来完成
注意点
- 注意:先序遍历是从上往下看,中序遍历和后序遍历是从下往上看
- 以根访问顺序决定是什么遍历
- 左子树都是优先右子树
自己的解法实现
#!/usr/bin/env python
# Definition for a binary tree node.
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
class Solution:
def inorderTraversal(self, root: TreeNode) -> List[int]:
if not root: return []
stack = []
res = []
node = root
while node or stack:
while node:
stack.append(node)
node = node.left
node = stack.pop()
res.append(node.val)
node = node.right
return res
def inorderTraversal2(self, root: TreeNode) -> List[int]:
def inorder(node, res):
if node is None: return
inorder(node.left, res)
res.append(node.val)
inorder(node.right, res)
res = []
inorder(root, res)
return res
网上比较优秀的解法
解法一
定义 inorder(root) 表示当前遍历到 root 节点的答案,那么按照定义,我们只要递归调用 inorder(root.left) 来遍历 root 节点的左子树,然后将 root 节点的值加入答案,再递归调用inorder(root.right) 来遍历 root 节点的右子树即可,递归终止的条件为碰到空节点。
时间复杂度:O(n),其中 n 为二叉树节点的个数。二叉树的遍历中每个节点会被访问一次且只会被访问一次。
空间复杂度:O(n),空间复杂度取决于递归的栈深度,而栈深度在二叉树为一条链的情况下会达到 O(n) 的级别。
def inorderTraversal2(self, root: TreeNode) -> List[int]:
def inorder(node, res):
if node is None: return
inorder(node.left, res)
res.append(node.val)
inorder(node.right, res)
res = []
inorder(root, res)
return res
解法二
颜色标记法:
- 使用颜色标记节点的状态,新节点为白色,已访问的节点为灰色。
- 如果遇到的节点为白色,则将其标记为灰色,然后将其右子节点、自身、左子节点依次入栈。
- 如果遇到的节点为灰色,则将节点的值输出。
- 如要实现前序、后序遍历,只需要调整左右子节点的入栈顺序即可。
def inorderTraversal5(self, root: TreeNode) -> List[int]:
WHITE, GREY = 0, 1
res = []
stack = [(WHITE, root)]
while stack:
color, node = stack.pop()
if node is None: continue
if color == WHITE:
stack.append((WHITE, node.right))
stack.append((GREY, node))
stack.append((WHITE, node.left))
else:
res.append(node.val)
return res
解法三
二叉树的中序遍历,在遍历时会先访问根节点,然后是左子树,再是右子树,只不过处理节点值是放在访问完左子树之后(这就是区别于先序、后序遍历的地方)。
最重点的内容就是:不管是先序中序还是后序,查找流程都是从上到下,先左后右。只是输出的时机不同。
先序就是发现了先输出,再先左后右。
中序就是发现了先存着,当左边遍历完了,再把存着的输出出来。
后序就是发现了先存着,当左边和右边都遍历完了,再把存着的输出出来。
def inorderTraversal8(self, root: TreeNode) -> List[int]:
# 递归1:二叉树遍历最易理解和实现版本
if not root: return []
# 前序递归
# return [root.val] + self.preorderTraversal(root.left) + self.preorderTraversal(root.right)
# 中序递归
return self.inorderTraversal8(root.left) + [root.val] + self.inorderTraversal8(root.left)
# 后序递归
# return self.postorderTraversal(root.left) + self.postorderTraversal(root.right) + [root.val]
def inorderTraversal9(self, root: TreeNode) -> List[int]:
res = []
# 通用模板,可以适应不同的题目,添加参数、增加返回条件、修改进入递归条件、自定义返回值
def dfs(node):
if not node: return
# 前序递归
# res.append(node.val)
# dfs(node.left)
# dfs(node.right)
# 中序递归
dfs(node.left)
res.append(node.val)
dfs(node.right)
# 后序递归
# dfs(node.left)
# dfs(node.right)
# res.append(node.val)
dfs(root)
return res
def inorderTraversal10(self, root: TreeNode) -> List[int]:
# 迭代2:前、中、后序遍历通用模板(只需一个栈的空间)
if not root: return []
res = []
stack = []
node = root
# 中序,模板:先用指针找到每颗子树的最左下角,然后进行进出栈操作
while stack or node:
while node:
stack.append(node)
node = node.left
node = stack.pop()
res.append(node.val)
node = node.right
return res
# # 前序,相同模板
# while stack or cur:
# while cur:
# res.append(cur.val)
# stack.append(cur)
# cur = cur.left
# cur = stack.pop()
# cur = cur.right
# return res
# # 后序,相同模板
# while stack or cur:
# while cur:
# res.append(cur.val)
# stack.append(cur)
# cur = cur.right
# cur = stack.pop()
# cur = cur.left
# return res[::-1]
# 迭代3:标记法迭代(需要双倍的空间来存储访问状态):
# 前、中、后、层序通用模板,只需改变进栈顺序或即可实现前后中序遍历,
# 而层序遍历则使用队列先进先出。0表示当前未访问,1表示已访问。
def inorderTraversal11(self, root: TreeNode) -> List[int]:
if not root: return []
res = []
stack = [(0, root)]
while stack:
flag, node = stack.pop()
if not node: continue
if flag == 0:
# 前序,标记法
# stack.append((0, node.right))
# stack.append((0, node.left))
# stack.append((1, node))
# # 后序,标记法
# stack.append((1, cur))
# stack.append((0, cur.right))
# stack.append((0, cur.left))
# # 中序,标记法
stack.append((0, node.right))
stack.append((1, node))
stack.append((0, node.left))
else:
res.append(node.val)
return res
def inorderTraversal12(self, root: TreeNode) -> List[int]:
if not root: return []
res = []
queue = [(0, root)]
while queue:
flag, node = queue.pop(0)
if not node: continue
if flag == 0:
# 层序遍历这三个的顺序无所谓,因为是队列,只弹出队首元素
queue.append((1, node.left))
queue.append((0, node))
queue.append((0, node.right))
else:
res.append(node.val)
return res
对自己解法的改进
颜色标记法和通用模板要好好学习
相关知识总结和思考
深入思考:对于这些题目,还是会处于一看就懂,写了会忘的阶段,还是要多多练习