二叉树层序遍历介绍
首先将每一层的节点放入一个队列中,然后遍历这个队列,同时将遍历到的节点的子节点也加入到队列中,直到队列为空。
基本模版:
void traverse(TreeNode root) {
if (root == null) return;
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
while (!q.isEmpty()) {
TreeNode cur = q.poll();
// 层序遍历位置
System.out.println(cur.val);
if (cur.left != null) q.offer(cur.left);
if (cur.right != null) q.offer(cur.right);
}
}
如果过程中需要分别得到每一层的各元素,则可改为:
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
if (root == null) return res;
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
while (!q.isEmpty()) {
int count = q.size(); // 记录当前层节点数
// 对当前行所有元素遍历操作
for (int i = 0; i < count; i++) {
TreeNode cur = q.poll();
// 操作每一层的各个元素
System.out.println(cur.val);
if (cur.left != null) q.offer(cur.left);
if (cur.right != null) q.offer(cur.right);
}
}
return res;
}
102. 二叉树的层序遍历
思路
层序遍历一个二叉树。就是从左到右一层一层的去遍历二叉树。这种遍历的方式和我们之前讲过的都不太一样。
需要借用一个辅助数据结构即队列来实现,队列先进先出,符合一层一层遍历的逻辑,而是用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。
而这种层序遍历方式就是图论中的广度优先遍历,只不过我们应用在二叉树上。
代码实现(java)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res;
Queue<TreeNode> 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++) {
TreeNode node = queue.poll();
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. 二叉树的层序遍历Ⅱ
思路
与层序遍历一致,只不过在最后将结果反转即可
代码实现(java)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<List<Integer>> levelOrderBottom(TreeNode root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res;
Queue<TreeNode> 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++) {
TreeNode node = queue.poll();
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;
}
}
199. 二叉树的右视图
思路
层序遍历,统计每层的最后一个结点即可,即每层循环的最后一个i == size - 1
代码实现(java)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> rightSideView(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) return res;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
if (i == (size - 1)) res.add(node.val);
if (node.left != null) queue.add(node.left);
if (node.right != null) queue.add(node.right);
}
}
return res;
}
}
637. 二叉树的层平均值
思路
统计每层结点和,然后用 求出的和 除以 该层节点数,接入结果集即可
代码实现(java)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Double> averageOfLevels(TreeNode root) {
List<Double> res = new ArrayList<>();
if (root == null) return res;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
int size = queue.size();
double sum = 0.0;
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
sum += node.val;
if (node.left != null) queue.add(node.left);
if (node.right != null) queue.add(node.right);
}
res.add(sum / size);
}
return res;
}
}
429. N叉树的层序遍历
思路
只是将左右结点改为了孩子结点的集合,加入队列时遍历孩子结点集合即可
代码实现(java)
/*
// Definition for a Node.
class Node {
public int val;
public List<Node> children;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, List<Node> _children) {
val = _val;
children = _children;
}
};
*/
class Solution {
public List<List<Integer>> levelOrder(Node root) {
List<List<Integer>> res = new ArrayList<>();
if (root == null) return res;
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 node = queue.poll();
list.add(node.val);
if (node.children.size() != 0) {
for (Node cnode : node.children) {
queue.add(cnode);
}
}
}
res.add(list);
}
return res;
}
}
515. 在每个树行中找最大值
思路
在每层循环中,依次比较取最大值即可
代码实现(java)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public List<Integer> largestValues(TreeNode root) {
List<Integer> res = new ArrayList<>();
if (root == null) {
return res;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while(!queue.isEmpty()) {
int size = queue.size();
int max = Integer.MIN_VALUE;
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
max = Math.max(max, node.val);
if (node.left != null) queue.add(node.left);
if (node.right != null) queue.add(node.right);
}
res.add(max);
}
return res;
}
}
116. 填充每个节点的下一个右侧节点指针
思路
- 在遍历每层时,先取出头结点
- 然后再依次遍历头结点后面的结点,通过指针的后移,连接后面各个结点即可
代码实现(java)
/*
// Definition for a Node.
class Node {
public int val;
public Node left;
public Node right;
public Node next;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, Node _left, Node _right, Node _next) {
val = _val;
left = _left;
right = _right;
next = _next;
}
};
*/
class Solution {
public Node connect(Node root) {
if (root == null) return root;
Queue<Node> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
int size = queue.size();
// 记录本层的头结点, 同时将其左右结点加入
Node cur = queue.poll();
if (cur.left != null) queue.add(cur.left);
if (cur.right != null) queue.add(cur.right);
// 接着遍历同层的其他结点,然后通过头结点一个一个循环连接起来即可
// 注意这里从1开始,因为头结点已经被取出,循环时少一个元素
for (int i = 1; i < size; i++) {
Node node = queue.poll();
if (node.left != null) queue.add(node.left);
if (node.right != null) queue.add(node.right);
cur.next = node;
cur = node;
}
}
return root;
}
}
117. 填充每个节点的下一个右侧节点指针 II
思路
这题与116题唯一的区别就是不是一颗完美二叉树,但是其实思路和解题方法完全一致
代码实现(java)
/*
// Definition for a Node.
class Node {
public int val;
public Node left;
public Node right;
public Node next;
public Node() {}
public Node(int _val) {
val = _val;
}
public Node(int _val, Node _left, Node _right, Node _next) {
val = _val;
left = _left;
right = _right;
next = _next;
}
};
*/
class Solution {
public Node connect(Node root) {
if (root == null) return root;
Queue<Node> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
int size = queue.size();
// 记录本层的头结点, 同时将其左右结点加入
Node cur = queue.poll();
if (cur.left != null) queue.add(cur.left);
if (cur.right != null) queue.add(cur.right);
// 接着遍历同层的其他结点,然后通过头结点一个一个循环连接起来即可
// 注意这里从1开始,因为头结点已经被取出,循环时少一个元素
for (int i = 1; i < size; i++) {
Node node = queue.poll();
if (node.left != null) queue.add(node.left);
if (node.right != null) queue.add(node.right);
cur.next = node;
cur = node;
}
}
return root;
}
}
104. 二叉树的最大深度
思路
在层序遍历的每层循环中,对一个计数器count
进行累加操作,只要层序遍历在进行,说明层数还在增加,最后返回count即可
代码实现(java)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int maxDepth(TreeNode root) {
int count = 0;
if (root == null) return count;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
count++;
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
if (node.left != null) queue.add(node.left);
if (node.right != null) queue.add(node.right);
}
}
return count;
}
}
补充一个递归方法
算法会向下找到最深的节点,然后向上返回,每次向上返回一次就深度就+1,最终返回左右子树中的最大深度加上根节点即可
public int maxDepth(TreeNode root) {
if(root == null) return 0;
return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
}
111. 二叉树的最小深度
思路
- 在层序遍历过程中,还是对计数器
count
进行累加 - 只要发现右节点的左节点和右节点都为空,则说明该结点为叶子节点,这时直接返回count就是最小深度
代码实现(java)
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int minDepth(TreeNode root) {
int count = 0;
if (root == null) return count;
Queue<TreeNode> queue = new LinkedList<>();
queue.add(root);
while (!queue.isEmpty()) {
count++;
int size = queue.size();
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
if (node.left == null && node.right == null) return count;
if (node.left != null) queue.add(node.left);
if (node.right != null) queue.add(node.right);
}
}
return count;
}
}
103. 二叉树的锯齿形层序遍历
思路
本题需要锯齿形层序遍历二叉树(先从左到右,再从右到左,依次循环)
根据题意可知,奇数行从左到右遍历,偶数行从右到左遍历
所以在奇数行正常得到遍历序列加入结果集;而偶数行则要先将遍历序列反转然后再加入结果集
代码实现(java)
class Solution {
List<List<Integer>> res = new ArrayList<>();
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
if (root == null) return res;
int leave = 0; // 记录层数,奇数层正向,偶数层逆向
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
while (!q.isEmpty()) {
int count = q.size(); // 记录当前层节点数
List<Integer> temp = new ArrayList<>();
leave++;
for (int i = 0; i < count; i++) {
TreeNode cur = q.poll();
temp.add(cur.val);
if (cur.left != null) q.offer(cur.left);
if (cur.right != null) q.offer(cur.right);
}
// 偶数层将列表翻转
if (leave % 2 == 0) {
Collections.reverse(temp);
}
res.add(temp);
}
return res;
}
}