1.问题
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]
示例 2:
输入:root = [1]
输出:[[1]]
示例 3:
输入:root = []
输出:[]
提示:
- 树中节点数目在范围 [0, 2000] 内
- -1000 <= Node.val <= 1000
2.解题思路
2.1 队列
二叉树每层的遍历符合队列的特性,必须FIFO(first in first out),再遍历每层完成后,可以给定一个标记或者层数,表示该层已经遍历完毕,可以将此时的该层遍历结果输出。伪代码:
//定义队列
Queue q;
//结果集
List res;
//root 入队
q.add(root);
//给定一个标识,标记第一层遍历的结尾
q.add(null);
while(q不为空){
//出队
temp=q.peek();
//不是标识的话,入队root.left、root.right
if(temp不为null){
res.add(temp.val);
if(temp.left不为null){
q.add(temp.left);
}
if(temp.right不为null){
q.add(temp.right);
}
}
//否则,该层遍历完毕
else {
q.add(null);
}
}
复杂度分析:
- 时间复杂度:O(n),其中n为二叉树的节点数,每个节点访问一次
- 空间复杂度:O(n),队列的空间为二叉树的一层的节点数,最坏情况二叉树的一层为O(n)级
2.2 递归
根据二叉树的定义,不难看出,每个节点都有类似的性质。当遍历发生时,对于其左右子树同样适用相同的规则,非常适合递归。可以借鉴之前对于二叉树的前中后序遍历,既然可以用递归解决,那层次遍历也未尝不可。同样可以运用标记的思想,对于同一层,可以标记为相同的深度来进行遍历。伪代码:
void traverse(TreeNode root, int depth);
//计入子节点,则深度depth+1
//递归左右时深度记得加1
traverse(root.left, depth + 1);
traverse(root.right, depth + 1);
//每个节点值放入对应的二维数组相应行
res[depth - 1].push_back(root->val);
复杂度分析
- 时间复杂度:O(n),n为节点数量,DFS对每个节点访问一次,因此递归调用n次,每次调用执行常数次操作,时间复杂度O(n)。
- 空间复杂度:O(n),空间复杂度在于递归调用深度和每次递归调用辅助空间,辅助空间为常数级,与节点深度相关,当节点深度为n时最大,为O(n)。
3.代码
import java.util.*;
/*
* public class TreeNode {
* int val = 0;
* TreeNode left = null;
* TreeNode right = null;
* }
*/
public class Solution {
/**
* 利用队列的性质
* @param root TreeNode类
* @return int整型ArrayList<ArrayList<>>
*/
public ArrayList<ArrayList<Integer>> levelOrder (TreeNode root) {
if (null == root) {
return new ArrayList<>();
}
//结果
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
//每层临时结果
ArrayList<Integer> temp = new ArrayList<>();
TreeNode node;
//队列
LinkedList<TreeNode> list = new LinkedList<TreeNode>();
list.add(root);
//给定个 层标识
list.add(null);
//遍历队列
while (!list.isEmpty()) {
node = list.removeFirst();
if (null != node) {
temp.add(node.val);
if (null != node.left) {
list.add(node.left);
}
if (null != node.right) {
list.add(node.right);
}
}
//为null节点,说明这一层已经遍历完成
else {
//这里一定要判断下,如果为空,表明二叉树已经遍历完成了
if (!temp.isEmpty()) {
res.add(temp);
temp = new ArrayList<>();
list.add(null);
}
}
}
return res;
}
//记录输出
ArrayList<ArrayList<Integer> > res = new ArrayList();
//递归
public ArrayList<ArrayList<Integer>> levelOrder (TreeNode root) {
if(root == null)
//如果是空,则直接返回
return res;
//递归层次遍历
traverse(root, 0);
return res;
}
//临时结果集
ArrayList<Integer> row;
void traverse(TreeNode root, int depth) {
if(root != null){
//新的一层: 对于二维res来说,将根视为第0层,树的深度正好等于一维res的个数
if(res.size() == depth){
row = new ArrayList();
res.add(row);
//读取该层的一维数组,将元素加入末尾
}else{
row = res.get(depth);
}
row.add(root.val);
}
else
return;
//递归左右时深度记得加1
traverse(root.left, depth + 1);
traverse(root.right, depth + 1);
}
}