题目1
这个问题实际上就是考察树的广度优先搜索,也就是按层遍历,BFS一般借助队列实现。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public int[] levelOrder(TreeNode root) {
if (root == null) // 空树则返回空数组
return new int[0];
Queue<TreeNode> q = new LinkedList<> (); // 借助一个队列,通过 BFS 实现按层遍历二叉树
ArrayList<Integer> tmp =new ArrayList<> (); // 申请一个动态数组 ArrayList 动态添加节点值
q.offer(root); // 根结点先入队
while (q.size() != 0) {
TreeNode node = q.poll(); // 取出当前队首元素
tmp.add(node.val);
if(node.left != null) q.offer(node.left); // 左子节点入队
if(node.right != null) q.offer(node.right); // 右子节点入队
}
// 将 ArrayList 转为 int数组并返回
int[] res = new int[tmp.size()];
for (int i=0; i<res.length; i++) {
res[i] = tmp.get(i);
}
return res;
}
}
题目2:二叉树的层序遍历
在前面的基础上稍作改进,每次记录下当前层的节点个数,将本层全部节点打印到一行,并将下一层全部节点加入队列,以此类推,即可分为多行打印。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
if (root == null) return new ArrayList<List<Integer>> ();
List<List<Integer>> res = new ArrayList<> ();
Queue<TreeNode> q = new LinkedList<> (); // BFS辅助队列
q.offer(root);
while(!q.isEmpty()) {
int level_size = q.size(); // 记录当前队列长度,即为这一层的节点个数
ArrayList<Integer> current_level = new ArrayList<> (); // 申请一个存放当前这一层的所有节点的临时列表
for(int i=0; i<level_size; i++) {
TreeNode node = q.poll();
current_level.add(node.val);
if(node.left != null) q.offer(node.left); // 若遍历到的节点有左子节点,也入队
if(node.right != null) q.offer(node.right); // 若遍历到的节点有右子节点,也入队
}
res.add(current_level); // 将当前层的临时列表加入最终返回结果中
}
return res;
}
}
题目3:之字形顺序打印二叉树
解析一下题目要求:
- 从上到下按层打印
- 每一层打印到一行
- 奇数层顺序打印(从左到右),偶数层倒序打印(从右到左)
解法一:层序遍历 + 双端队列
利用双端队列两端即可添加元素的特性,可以解决这个问题。具体来说,在采用 BFS 循环打印的过程中,将奇偶层逻辑拆分:
打印奇数层时,从左到右打印,先左孩子后右孩子加入下层节点;
打印偶数层时,从右到左打印,先右孩子后左孩子加入下层节点,且采用头插法,保证添加的下层节点之间符合在树中原有的先后顺序。
Java
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
if(root == null) return new ArrayList<List<Integer>> ();
Deque<TreeNode> q = new LinkedList<> ();
List<List<Integer>> res = new ArrayList<> ();
q.addLast(root);
while (!q.isEmpty()) {
// 奇数层,从左到右打印
List<Integer> tmp = new ArrayList<> ();
int level_size = q.size();
for(int i=0; i<level_size; i++) {
TreeNode node = q.removeFirst(); // 节点从队首出队,才能实现从左到右的顺序
tmp.add(node.val);
// 先左后右加入下层节点,并且采用尾插法
if(node.left != null) q.addLast(node.left);
if(node.right != null) q.addLast(node.right);
}
res.add(tmp);
if(q.isEmpty()) break;
// 偶数层,从右到左打印
tmp = new ArrayList<> ();
level_size = q.size();
for(int i=0; i<level_size; i++) {
TreeNode node = q.removeLast(); // 节点从队尾出队,才能实现从右到左的顺序
tmp.add(node.val);
// 先右后左加入下层节点,并且采用头插法
//(这是由于此时最先出队的是最右边的节点,添加其子结点到下一层时,我们要保证原有的顺序,头插法可以保证其子结点也位于下一层的最右边)
if(node.right != null) q.addFirst(node.right);
if(node.left != null) q.addFirst(node.left);
}
res.add(tmp);
}
return res;
}
}
复杂度分析:
时间复杂度 O(N) : N 为二叉树的节点数量,即 BFS 需循环 N 次,占用 O(N) ;每次循环双端队列的队首和队尾的添加和删除操作的时间复杂度均为 O(1) 。
空间复杂度 O(N) : 最差情况下,即当树为满二叉树时,最多会有 (N+1)/2 个节点同时在 deque 中,使用 O(N) 大小的额外空间。
解法二:层序遍历 + 偶数层进行倒序
此方法的优点是,无需双端队列,只要在 BFS 循环中,当判断当前层为偶数层时,我们就对存储当层节点的列表进行反转执行倒序操作。
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
if (root == null) return new ArrayList<List<Integer>> ();
Queue<TreeNode> q = new LinkedList<> ();
List<List<Integer>> res = new ArrayList<> ();
q.offer(root);
while(!q.isEmpty()) {
int level_size = q.size();
ArrayList<Integer> tmp = new ArrayList<> ();
for(int i=0; i<level_size; i++) {
TreeNode node = q.poll();
tmp.add(node.val);
if (node.left != null) q.offer(node.left);
if (node.right != null) q.offer(node.right);
}
// 若 res 的长度(上面已经打印了多少层)为奇数,说明当前是偶数层,则对 tmp执行倒序操作。
if ((res.size() & 1)==1) Collections.reverse(tmp);
res.add(tmp);
}
return res;
}
}
复杂度分析:
时间复杂度 O(N) : N 为二叉树的节点数量,即 BFS 需循环 N 次,占用 O(N) ;每次循环双端队列的队首和队尾的添加和删除操作的时间复杂度均为 O(1) 。
空间复杂度 O(N) : 最差情况下,即当树为满二叉树时,最多会有 (N+1)/2 个节点同时在 deque 中,使用 O(N) 大小的额外空间。
参考
https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-ii-lcof/solution/mian-shi-ti-32-ii-cong-shang-dao-xia-da-yin-er-c-5/
https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-iii-lcof/solution/mian-shi-ti-32-iii-cong-shang-dao-xia-da-yin-er–3/