public static List<Integer> getResult(TreeNote root) {
if (root == null) return new ArrayList<>();
List<Integer> list = new ArrayList<>();
LinkedList<TreeNote> queue = new LinkedList<>();
// 放入根节点
queue.add(root);
// 只有当队列不为空的时候
while (queue.size() > 0) {
TreeNote treeNote = queue.remove();
list.add(treeNote.val);
if (treeNote.leftNode != null) {
queue.add(treeNote.leftNode);
}
if (treeNote.rightNode != null) {
queue.add(treeNote.rightNode);
}
}
return list;
}
二叉树的层序遍历
给你二叉树的根节点 root ,返回其节点值的 层序遍历 。 (即逐层地,从左到右访问所有节点)
输入:root = [3,9,20,null,null,15,7]
输出:[[3],[9,20],[15,7]]
可以看出,基本的步骤都一样,唯一的差别在于,现在需要将每一层的节点元素放入单独的list集合里面去
public List<List<Integer>> levelOrder(TreeNode root) {
if(root == null) return new ArrayList<List<Integer>> ();
// 记录结果
List<List<Integer>> res = new ArrayList<List<Integer>>();
LinkedList<TreeNode> queue= new LinkedList<>();
// 添加root
queue.add(root);
while(queue.size()>0){
// 记录当前一行的节点条数
int size = queue.size();
ArrayList<Integer> list = new ArrayList<>();
// 队列元素放入list
for(int i =0;i<size;i++){
TreeNode node =queue.remove();
list.add(node.val);
if(node.left!=null){
queue.add(node.left);
}
if(node.right!=null){
queue.add(node.right);
}
}
res.add(list);
}
return res;
}
107. 二叉树的层序遍历 II
给你二叉树的根节点 root ,返回其节点值 自底向上的层序遍历 。 (即按从叶子节点所在层到根节点所在的层,逐层从左向右遍历)
输入:root = [3,9,20,null,null,15,7]
输出:[[15,7],[9,20],[3]]
初始想法就是依然正向添加元素,然后将List里面元素逆序排序list,但是不知道是否可行。
public List<List<Integer>> levelOrderBottom(TreeNode root) {
if(root == null) return new ArrayList<List<Integer>>();
ArrayList<List<Integer>> res = new ArrayList<List<Integer>>();
LinkedList<TreeNode> queue = new LinkedList<>();
queue.add(root);
while(queue.size()>0){
int size = queue.size();
ArrayList<Integer> list = new ArrayList<>();
for(int i=0;i<size;i++){
TreeNode node = queue.remove();
list.add(node.val);
if(node.left!=null) queue.add(node.left);
if(node.right!=null) queue.add(node.right);
}
res.add(list);
}
// 工具逆序
Collections.reverse(res);
return res;
}
这种思路就是一开始定义列表,将新列表添加至列表的头部,就完成了逆序。
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> levelOrder = new LinkedList<List<Integer>>();
if(root == null) return levelOrder;
LinkedList<TreeNode> queue = new LinkedList<>();
queue.offer(root);
while(queue.size()>0){
int size = queue.size();
List<Integer> level = new ArrayList<Integer>();
for(int i=0;i<size;i++){
TreeNode node = queue.poll();
level.add(node.val);
if(node.left!=null) queue.add(node.left);
if(node.right!=null) queue.add(node.right);
}
levelOrder.add(0,level);
}
return levelOrder;
}
两种思路都差不多,都是将列表里面的列表元素逆序。
103. 二叉树的锯齿形层序遍历
给你二叉树的根节点 root ,返回其节点值的 锯齿形层序遍历 。(即先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行)。
输入:root = [3,9,20,null,null,15,7]
输出:[[3],[20,9],[15,7]]
依然是先写出简单方法,只不过列表里面的列表元素需要根据左右左右进行排序,思路主要是先定义一个布尔状态标识现在是先左子树还是右子树。 添加列表元素的时候采用Deque来存储,因为里面有addFirst和addLast方法,当此时是从左往右遍历,那么就将其添加到last位置,最后需要转换为ArrayList。
Deque特点:双端队列,两端都可添加和删除元素。
Queue特点:单端队列,只能一段添加,另一端删除元素。
这一题主要考察的是树和双端队列。
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
if(root == null) return new ArrayList<List<Integer>>();
List<List<Integer>> res = new LinkedList<List<Integer>>();
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
Boolean isOrderLeft = true;
while(queue.size()>0){
int size = queue.size();
// 双端队列,存储元素
Deque<Integer> list = new LinkedList<>();
for(int i=0;i<size;i++){
TreeNode node = queue.remove();
//如果当前遍历方向为从右到左,则将当前节点值添加到双端队列的左侧。
//如果当前遍历方向为从左到右,则将当前节点值添加到双端队列的右侧。
if(!isOrderLeft){
list.addFirst(node.val);
}else{
list.addLast(node.val);
}
if(node.left!=null) queue.add(node.left);
if(node.right!=null) queue.add(node.right);
}
// 转换普通列表
res.add(new ArrayList<>(list));
// 切换遍历方向
isOrderLeft = !isOrderLeft;
}
return res;
}
时间复杂度:O(n)n为节点个数
空间复杂度:O(n)使用双端队列存储n个元素
总结:关于一些常用的特性需要多留意
N 叉树的层序遍历
给定一个 N 叉树,返回其节点值的层序遍历。(即从左到右,逐层遍历)。
树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)
输入:root = [1,null,3,2,4,null,5,6]
输出:[[1],[3,2,4],[5,6]]
依然先写出简单的层序遍历,但是这一题是n叉树,意味着原来的左右子树是无法使用了,但是仔细思考一下,原来的左右子树也是子树,只不过现在采用List存储子树,只需要遍历子树,队列重新遍历添加子树即可。
public List<List<Integer>> levelOrder(Node root) {
if(root == null) return new ArrayList<List<Integer>>();
List<List<Integer>> res = new ArrayList<List<Integer>>();
Queue<Node> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()){
int size = queue.size();
List<Integer> list = new ArrayList<>();
for(int i=0;i<size;i++){
Node temp = queue.remove();
list.add(temp.val);
// 遍历子树
if(temp.children!=null){
for(Node child:temp.children){
queue.add(child);
}
}
}
res.add(list);
}
return res;
}
时间复杂度:O(n)遍历每个子树
空间复杂度:O(n) 队列使用空间
可以很清晰看出,对于层序遍历,无非就是在简单版本的基础上继续扩充,简单版本一定是需要会的。