代码随想录算法训练营第十一天(二叉树篇)|Leetcode144二叉树的前序遍历,Leetcode145二叉树的后序遍历,Leetcode94二叉树的中序遍历,Leetcode102二叉树的层序遍历
Leetcode 144 二叉树的前序遍历
题目链接: 二叉树的前序遍历
给定一棵二叉树的根节点,返回该二叉树通过前序遍历得到的节点数组
思路: 首先回忆前序遍历。二叉树的前序遍历,即是将二叉树中节点按照 "中左右" 的顺序进行遍历,得到的节点数组即为前序遍历的结果。
考虑以下二叉树:
1
/ \
2 3
/ \ \
4 5 6
其前序遍历得到的结果为 [1,2,3,4,5,6]
首先从根节点 1 开始,随后处理它的左子节点 2,接着是它的右子节点 3。接着是 2 的左子节点 4, 2 的右子节点 5,最后是 3 的右子节点 6。完成前序遍历的过程
为了彻底理解前序遍历的实现,以下将给出递归法,迭代法的二叉树前序遍历实现。
# 递归法
class Solution:
def traverse(self, cur: Optional[TreeNode], result: List[int]) -> None:
# 递归终止条件: 当前节点为空
if cur is None:
return
# 分别处理中-左-右节点
result.append(cur.val)
self.traverse(cur.left, result)
self.traverse(cur.right , result)
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
result = []
self.traverse(root, result)
return result
# 迭代法
class Solution:
def preorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
result = []
myStack = [] # 通过将节点按照一定的顺序压入栈,并处理栈顶节点,实现前序遍历
if root is None:
return result
myStack.append(root)
# 只要栈中还存在节点元素,就继续处理
while myStack:
# 栈顶元素即为当前正在处理的节点
cur = myStack.pop()
result.append(cur.val)
# 根据栈后入先出的特性,先将当前节点的右孩子压入栈中,然后是左孩子。这样左孩子先出栈。
if cur.right is not None:
myStack.append(cur.right)
if cur.left is not None:
myStack.append(cur.left)
return result
Leetcode 145 二叉树的后序遍历
题目链接: 二叉树的后序遍历
给定一棵二叉树的根节点,返回二叉树经过后序遍历得到的节点数组
思路: 后序遍历,即是将二叉树中节点按照 "左右中" 的顺序进行遍历,得到的节点数组即为后序遍历的结果。
考虑以下二叉树:
1
/ \
2 3
/ \ \
4 5 6
其后序遍历得到的结果为 [4,5,2,6,3,1]。首先看二叉树的左子树,左节点为 4,右节点为 5,中间节点为 2;然后看二叉树的右子树,右节点为 6,中间节点为 3;最后是二叉树的根节点 1
此处同样给出递归法,迭代法的实现。除此之外,还给出利用标志位标记节点的迭代法的实现。
具体代码实现
# 递归法
class Solution:
def traverse(self, cur: Optional[TreeNode], result: List[int]) -> None:
# 递归终止条件: 当前节点为空
if cur is None:
return
# 按照左右中的顺序遍历节点
self.traverse(cur.left, result)
self.traverse(cur.right, result)
result.append(cur.val)
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
result = []
self.traverse(root, result)
return result
# 迭代法
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
result = []
myStack = [] # 将节点压入栈中
if root is None:
return result
myStack.append(root)
# 此处压栈时按照中右左的顺序处理节点,最后将得到的结果进行反转,即得到按照左右中顺序处理的后序遍历的结果
while myStack:
cur = myStack.pop()
result.append(cur.val)
if cur.left is not None:
myStack.append(cur.left)
if cur.right is not None:
myStack.append(cur.right)
return result[::-1]
我们利用迭代法实现二叉树遍历时,最大的难题在于,如何处理好当前遍历的节点与实际应当处理的节点的不同。之前我们通过压栈解决了这一问题,但是这将导致前中后序二叉树遍历的代码写法不一致,难以记忆。
因此,我们可以利用标志位标记节点,仅收获标记位符合要求的节点的值,这样统一了代码写法,更容易理解
# 利用标志位标记节点的迭代法实现
class Solution:
def postorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
result = []
myStack = []
if root is not None:
myStack.append([root, False])
while myStack:
node, visited = myStack.pop()
# 仅将标志位为True的节点值加入到结果中
if visited:
result.append(node.val)
continue
# 遍历完中间节点,将中间节点的标志位设置为True,供后续取用
myStack.append([node, True])
# 将右子节点,左子节点压入栈中
if node.right is not None:
myStack.append([node.right, False])
if node.left is not None:
myStack.append([node.left, False])
return result
Leetcode 94 二叉树的中序遍历
题目链接: 二叉树的中序遍历
给定一棵二叉树的根节点,返回该二叉树通过中序遍历得到的节点数组
思路: 中序遍历,即按照 "左中右" 的顺序遍历二叉树节点。
考虑以下二叉树:
1
/ \
2 3
/ \ \
4 5 6
其中序遍历得到的结果为 [4,2,5,1,3,6]。首先是左子树的左节点 4,左子树的中间节点 2,左子树的右节点 5;然后是根节点 1,然后是右子树的中间节点 3,右子树的右节点 6。
以下同样给出递归法,迭代法,以及带标志位的迭代法
具体代码实现
# 递归法
class Solution:
def traverse(self, cur: Optional[TreeNode], result: List[int]) -> None:
if cur is None:
return
self.traverse(cur.left, result)
result.append(cur.val)
self.traverse(cur.right, result)
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
result = []
self.traverse(root, result)
return result
# 迭代法
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
result = []
myStack = []
cur = root
# 深度优先搜索
while cur is not None or myStack:
# 将中间节点入栈供后续取用,寻找最深的左子节点
if cur is not None:
myStack.append(cur)
cur = cur.left
else:
# 处理完中间节点后,再处理右节点
cur = myStack.pop()
result.append(cur.val)
cur = cur.right
return result
# 带标志位的迭代法
class Solution:
def inorderTraversal(self, root: Optional[TreeNode]) -> List[int]:
result = []
myStack = []
if root is not None:
myStack.append([root, False])
while myStack:
node, visited = myStack.pop()
# 当前节点先前已经遍历过,收获其结果即可
if visited:
result.append(node.val)
continue
# 右节点压栈
if node.right is not None:
myStack.append([node.right, False])
# 已经遍历过中间节点了,将其标志位改为True,下次遇到时收获其值
myStack.append([node, True])
# 左节点压栈
if node.left is not None:
myStack.append([node.left, False])
return result
Leetcode 102 二叉树的层序遍历
题目链接: 二叉树的层序遍历
给定一棵二叉树的根节点,返回该二叉树中通过层序遍历得到的节点数组
思路: 层序遍历,即按照 "层层深入" 的顺序遍历二叉树节点。只有当遍历完当前层以后,才会遍历下一层,直至遍历完二叉树中的所有层。
考虑以下二叉树:
1
/ \
2 3
/ \ \
4 5 6
其层序遍历得到的结果为 [[1],[2,3],[4,5,6]]
我们可以使用队列解决这一问题: 当处理当前节点时,将当前节点的孩子节点放入队列中,直到处理完当前层级的节点后,将当前层级的一维节点数组插入到二维结果数组中
具体代码实现:
class Solution:
def levelOrder(self, root: Optional[TreeNode]) -> List[List[int]]:
from collections import deque
result = []
myQueue = deque()
if root is not None:
myQueue.append(root)
while myQueue:
# 统计当前层级的节点数量
size = len(myQueue)
levelResult = []
for _ in range(size):
node = myQueue.popleft() # 取出当前需要处理的节点
levelResult.append(node.val)
# 若孩子节点存在,将其插入到队列中
if node.left:
myQueue.append(node.left)
if node.right:
myQueue.append(node.right)
result.append(levelResult)
return result

浙公网安备 33010602011771号