题目介绍
描述:给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
示例:
二叉树:[3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回其层次遍历结果:
[
[3],
[9,20],
[15,7]
]
解题思路
递归算法的关键是要明确函数的「定义」是什么,然后相信这个定义,利用这个定义推导最终结果。
写树相关的算法,简单说就是,先搞清楚当前 root 节点该做什么,然后根据函数定义递归调用子节点,递归调用会让孩子节点做相同的事情。
二叉树题目的一个难点在于如何通过题目的要求思考出每一个节点需要做什么
如果根节点为空,则返回空列表,如果只有一个根节点,则返回只有根节点值的列表,然后根据宽度优先来依次遍历每一层。可以递归或者迭代
自己的解法实现
def levelOrder(self, root):
if not root: return []
stack, res = [root, ], []
while stack:
level = []
for _ in range(len(stack)):
node = stack.pop(0)
level.append(node.val)
if node.left:
stack.append(node.left)
if node.right:
stack.append(node.right)
res.append(level)
return res
def levelOrder2(self, root):
from collections import deque
if not root: return []
queue, res = deque([root]), []
while queue:
level = []
for _ in range(len(queue)):
node = queue.popleft()
level.append(node.val)
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
res.append(level)
return res
网上比较优秀的解法
解法一
广度优先遍历是按层层推进的方式,遍历每一层的节点。
广度优先需要用队列作为辅助结构,我们先将根节点放到队列中,然后不断遍历队列。
def levelOrder3(self, root):
if not root: return []
res = []
def dfs(index, node):
if len(res) < index:
res.append([])
res[index - 1].append(node.val)
# 递归的处理左子树,右子树,同时将层数index+1
if node.left:
dfs(index + 1, node.left)
if node.right:
dfs(index + 1, node.right)
dfs(1, root)
return res
解法二
def levelOrder4(self, root):
ans = []
self.dfs(root, 0, ans)
return ans
def dfs(self, root, level, ans):
if not root:
return
if len(ans) < level + 1:
ans.append([])
ans[level].append(root.val)
self.dfs(root.left, level + 1, ans)
self.dfs(root.right, level + 1, ans)
解法三
初始化: 当前层cur_level=[root],下一层next_level=[],结果集: [[i.val for i in cur_level]] 循环迭代更新当前层以及下一层,同时收集每一层结点值 循环结束条件:当前层以及下一层都为空
def levelOrder5(self, root):
if not root: return []
cur_level, nxt_level = [root], [] # 当前层结点以及下一层结点
res = [[node.val for node in cur_level]] # 遍历当前层
while cur_level or nxt_level:
for node in cur_level:
if node.left:
nxt_level.append(node.left)
if node.right:
nxt_level.append(node.right)
if nxt_level:
res.append([node.val for node in nxt_level])
cur_level, nxt_level = nxt_level, [] # 更新当前层以及下一层
return res
解法四
DFS 做本题的主要问题是: DFS 不是按照层次遍历的。为了让递归的过程中同一层的节点放到同一个列表中,在递归时要记录每个节点的深度 level。递归到新节点要把该节点放入 level 对应列表的末尾。 当遍历到一个新的深度 level,而最终结果 res 中还没有创建 level 对应的列表时,应该在 res 中新建一个列表用来保存该 level 的所有节点。
def levelOrder6(self, root):
res = []
self.level(root, 0, res)
return res
def level(self, root, level, res):
if not root: return
if len(res) == level: res.append([])
res[level].append(root.val)
if root.left:
self.level(root.left, level + 1, res)
if root.right:
self.level(root.right, level + 1, res)
相关知识总结和思考
相关知识:
递归(recursion)就是子程序(或函数)直接调用自己或通过一系列调用语句间接调用自己。该执行过程要求每一次节点中断调用其他方法,必须记录下该中断节点的环境信息,作用是为了调用结束返回结果之后原程序能够从上次中断位置起继续执行,在计算机中,通过一个栈结构来实现该效果(栈:先进后出):
递归与循环的区别与联系
相同点: (1)都是通过控制一个变量的边界(或者多个),来改变多个变量为了得到所需要的值,而反复而执行的; (2)都是按照预先设计好的推断实现某一个值求取;(请注意,在这里循环要更注重过程,而递归偏结果一点)
不同点: (1)递归通常是逆向思维居多,“递”和“归”不一定容易发现;而循环从开始条件到结束条件,包括中间循环变量,都需要表达出来。
简单的来说就是:用循环能实现的,递归一般可以实现,但是能用递归实现的,循环不一定能。因为有些题目
①只注重循环的结束条件和循环过程,而往往这个结束条件不易表达(也就是说用循环并不好写);
②只注重循环的次数而不注重循环的开始条件和结束条件