题目一 不分行从上到下打印二叉树
队列 BFS
使用广度优先可以遍历一幅有向图,树是图的一种特殊退化形式,从上到下按层遍历二叉树,从本质上来说就是广度优先遍历二叉树。
实现BFS可以使用一个队列,每次从队列中取出一个节点,将其子节点加入到队列中,知道队列为空。
由于题目要求输出一个数组,所以需要先知道树的节点数,因此可以使用递归先得到树的大小。
另一种方案是使用java提供的ArrayList, 最后将ArrayList的元素赋值给数组。
/**
* 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[]{};
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int n = nodeNums(root);
int[] ans = new int[n];
int index = 0;
// System.out.println(n);
while(!queue.isEmpty()){
TreeNode cur = queue.poll();
ans[index++] = cur.val;
if(cur.left != null) queue.offer(cur.left);
if(cur.right != null) queue.offer(cur.right);
}
return ans;
}
private int N = 0;
private int nodeNums(TreeNode node){
if(node.left == null && node.right == null){
return ++N;
}else{
++N;
}
if(node.left != null)
nodeNums(node.left);
if(node.right != null)
nodeNums(node.right);
return N;
}
}
题目二 分行从上到下打印二叉树
解法一
这题与第一题的不同在于要分行打印。第一种思路是从队列中每次取出当前层的所有元素加入list中,同时在队列中加入下一层所有元素,也就是取一层加下一层,知道最后队列为空
/**
* 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<>();
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
List<List<Integer>> ans = new ArrayList<>();
while(!queue.isEmpty()){
int floorSize = queue.size();
List<Integer> eachFloor = new ArrayList<>();
for(int i = 0; i < floorSize; i++){
TreeNode cur = queue.poll();
if(cur.left != null) queue.offer(cur.left);
if(cur.right != null) queue.offer(cur.right);
eachFloor.add(cur.val);
}
ans.add(eachFloor);
}
return ans;
}
}
解法二
第二种思路还是从队列中每次取一个节点,然后将其子节点加入队列尾部。
使用一个变量记录当前层剩余打印的节点数,使用另一个变量记录下一层的节点数。
每次取出一个节点当前层剩余的节点减少1;取出一个节点后队列中加入其子节点,记录下一层节点数;当前层剩余节点为0时说明当前层以及取完,进入下一层。
/**
* 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<>();
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
List<List<Integer>> ans = new ArrayList<>();
List<Integer> level = new ArrayList<>();
int nextLevel = 0;//记录下一层的节点数
int toBePrinted = 1;//当前层应打印的节点数
while(!queue.isEmpty()){
TreeNode cur = queue.poll();
level.add(cur.val);
toBePrinted--;
if(cur.left != null){
++nextLevel;
queue.offer(cur.left);
}
if(cur.right != null){
++nextLevel;
queue.offer(cur.right);
}
if(toBePrinted == 0){
ans.add(level);
level = new ArrayList<Integer>();
toBePrinted = nextLevel;
nextLevel = 0;
}
}
return ans;
}
}
题目三 之字形打印二叉树
以上面这颗二叉树为例,先打印节点3,然后将其子节点(9,20)保存到数据结构中。打印第二层时需要先打印20再打印9,所以是先进后出,可以使用“栈”保存(9,20)。打印第三层时从栈中先取出的是20,而打印需要先打印15,再打印7所以需要将7先压入栈,再将15压入栈。不同的层压栈顺序不一样所以需要两个栈交替使用。
下面的解法为:
- 定义两个栈:stack1保存“从左向右”打印的层节点,stack2保存从右向左打印的层节点
- stack1中先压入根节点,弹出根节点后,将其子节点按顺序压入stack2
- 从stack2中弹出所以节点并将其子节点按顺序压入stack1中
- 以此类推知道两个栈都为空
/**
* 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();
LinkedList<TreeNode> stack1 = new LinkedList<>();
LinkedList<TreeNode> stack2 = new LinkedList<>();
stack1.push(root);
boolean nextDirect = true; //下一层打印的方向false:从左到右,true:从右到左
List<List<Integer>> ans = new ArrayList<>();
while(!stack1.isEmpty() || !stack2.isEmpty()){
int size = nextDirect ? stack1.size() : stack2.size();
List<Integer> level = new LinkedList<>();
for(int i = 0; i < size; i++){
TreeNode node = nextDirect ? stack1.pop() : stack2.pop();
level.add(node.val);
if(nextDirect){
if(node.left != null)
stack2.push(node.left);
if(node.right != null)
stack2.push(node.right);
}else{
if(node.right != null)
stack1.push(node.right);
if(node.left != null)
stack1.push(node.left);
}
}
ans.add(level);
nextDirect = !nextDirect;
}
return ans;
}
}
相同的思路,一种更简洁的写法。定义一个数组存储两个栈:stack[0],stack[1];
使用两个变量current和next来交替使用这两个栈。每次从当前栈中按每次一个取出所有元素,将这些元素根据当前打印顺序压入另一个栈中。当前栈中元素为空时,将两个栈进行交替。
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
if(root == null) return new ArrayList();
LinkedList<TreeNode>[] stack = new LinkedList[]{new LinkedList(), new LinkedList()};
stack[0].push(root);
int current = 0;//标记打印顺序: 0:从左向右,1:从右向左
int next = 1;//下一层
List<List<Integer>> ans = new ArrayList<>();
List<Integer> level = new ArrayList<>();
while(!stack[0].isEmpty() || !stack[1].isEmpty()){
TreeNode node = stack[current].pop();
level.add(node.val);
if(current == 0){
if(node.left != null)
stack[next].push(node.left);
if(node.right != null)
stack[next].push(node.right);
}else{
if(node.right != null)
stack[next].push(node.right);
if(node.left != null)
stack[next].push(node.left);
}
if(stack[current].isEmpty()){
ans.add(level);
level = new ArrayList<>();
current = 1 - current;
next = 1 - next;
}
}
return ans;
}
}