剑指 offer 32 :从上到下打印二叉树
一
代码 001
广度优先搜索
使用队列
/**
* 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> queue = new LinkedList<>();
List<Integer> res = new ArrayList<>();
queue.add(root);
while(!queue.isEmpty()){
TreeNode p = queue.peek();
queue.poll();
res.add(p.val);
if(p.left!=null){
queue.offer(p.left);
}
if(p.right!=null){
queue.offer(p.right);
}
}
int[] finalRes = new int[res.size()];
for(int i=0;i<res.size();i++){
finalRes[i] = res.get(i);
}
return finalRes;
}
}
代码 002
/**
* 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> queue = new LinkedList<>();
List<Integer> res = new ArrayList<>();
queue.add(root);
while(!queue.isEmpty()){
TreeNode p = queue.poll();
res.add(p.val);
if(p.left!=null){
queue.offer(p.left);
}
if(p.right!=null){
queue.offer(p.right);
}
}
int[] finalRes = new int[res.size()];
for(int i=0;i<res.size();i++){
finalRes[i] = res.get(i);
}
return finalRes;
}
}
时间复杂度
O
(
n
)
O(n)
O(n),
n
n
n是二叉树不为空的节点的个数,每个节点都要遍历一遍,进队列,出队列一次,并且节点的值存入结果数组中。
空间复杂度
O
(
n
)
O(n)
O(n),辅助队列。
二
代码 003
使用队列来保存将要打印的点。为了把二叉树的每一行单独打印到一行里,需要两个变量:一个变量表示在当前层中还没打印的节点数;另一个变量表示下一层节点的数目。变量toBePrinted表示当前层还没有打印的点数,而nextLevel表示下一层的节点数。如果一个节点有子节点,则把字节点加入到队列中,没增加一个子节点 nextLevel加 1。每打印一个节点toBePrinted减 1,当toBePrinted变为 0时,表示当前层的所有节点都打印完毕,可以继续打印下一层。
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
//root 为空的处理
Queue<TreeNode> queue = new LinkedList<>();
List<Integer> subRes = new ArrayList<>();
List<List<Integer>> res = new ArrayList<>();
int toBePrinted =1;
int nextLevel = 0 ;
if(root!=null){
queue.add(root);
}
while(!queue.isEmpty()){
TreeNode p = queue.poll();
subRes.add(p.val);
// System.out.print(p.val+"\t");
toBePrinted--;
if(p.left != null){
queue.add(p.left);
nextLevel++;
}
if(p.right!=null){
queue.add(p.right);
nextLevel++;
}
if(toBePrinted==0){
res.add(subRes);
subRes = new ArrayList<>();
toBePrinted = nextLevel;
nextLevel = 0;
// System.out.println();
}
}
return res;
}
}
代码 004
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
List<List<Integer>> res = new ArrayList<>();
if (root!=null){
queue.add(root);
}
while (!queue.isEmpty()){
List<Integer> subRes = new ArrayList<>();
for (int i=queue.size();i>0;i--){//设计极其巧妙!!!,先用了队列的长度,以后队列再增加也没影响
TreeNode p =queue.poll();
subRes.add(p.val);
// System.out.print(p.val+"\t");
if (p.left!=null){
queue.add(p.left);
}
if (p.right!=null){
queue.add(p.right);
}
}
res.add(subRes);
// System.out.println();
}
return res;
}
}
时间复杂度
O
(
n
)
O(n)
O(n)
空间复杂度
O
(
n
)
O(n)
O(n),辅助栈
三
代码 005
按之字形打印二叉树需要两个栈。在打印某一层的节点时,把下一层的节点保存到相应的栈里。如果当前打印的是奇数层,则先保存左子节点再保存右子节点到一个栈里,如果当前打印的是偶数层,则先保存右子节点再保存左子节点到另一个栈里。
/**
* 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) {
Stack<TreeNode> s1 = new Stack<>();
Stack<TreeNode> s2 = new Stack<>();
int level = 1;
List<Integer> subRes = new ArrayList<>();
List<List<Integer>> res = new ArrayList<>();
if(root!=null){
s1.push(root);
}
while(!s1.empty() || !s2.empty()){
if(level%2==1){
//当前是奇数层
//s1 出栈,子节点入栈 s2
while(!s1.empty()){
TreeNode p = s1.pop();
subRes.add(p.val);
//子节点入栈
if(p.left!=null){
s2.push(p.left);
}
if(p.right!=null){
s2.push(p.right);
}
}
res.add(subRes);
subRes = new ArrayList<>();
}else{
//当前层是偶数层
//s2 出栈,s1 入栈
while(!s2.empty()){
TreeNode p = s2.pop();
subRes.add(p.val);
//子节点入栈
if(p.right!=null){
s1.push(p.right);
}
if(p.left!=null){
s1.push(p.left);
}
}
res.add(subRes);
subRes = new ArrayList<>();
}
level++;
}
return res;
}
}
层序遍历+双端队列
依旧是层序遍历的框架,在保存 subRes的时候使用了双端队列,进行顺序的改变,偶数层变成逆序。
/**
* 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) {
Queue<TreeNode> queue = new LinkedList<>();
List<List<Integer>> res = new ArrayList<>();
if(root!=null){
queue.add(root);
// res.add(new ArrayList<>(root.val));
}
while(!queue.isEmpty()){
LinkedList<Integer> subRes = new LinkedList<>();
for(int i=queue.size();i>0;i--){
TreeNode p = queue.poll();
if(res.size()%2==1){
//奇数层
subRes.addFirst(p.val);
}else{
//偶数层
subRes.addLast(p.val);
}
if(p.left!=null){
queue.add(p.left);
}
if(p.right!=null){
queue.add(p.right);
}
}
res.add(subRes);
}
return res;
}
}
层序遍历+双端队列(奇偶层逻辑分离)
上面的代码简短,容易实现,但是需要判断每个节点所在层的奇偶性,也就是冗余了
N
N
N次判断。
通过将奇偶层逻辑拆分,可以消除冗余的判断
这个方法和第一种的方法很类似,只是没有使用两个栈
遍历的顺序不一样了
/**
* 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) {
Deque<TreeNode> queue = new LinkedList<>();
List<List<Integer>> res = new ArrayList<>();
if(root!=null){
queue.add(root);
}
while(!queue.isEmpty()){
//奇数层
List<Integer> subRes = new ArrayList<>();
for(int i=queue.size();i>0;i--){
TreeNode p = queue.pollFirst();
subRes.add(p.val);
if(p.left!=null){
queue.addLast(p.left);
}
if(p.right!=null){
queue.addLast(p.right);
}
}
res.add(subRes);
if(queue.isEmpty()){
break;
}
//偶数层
subRes = new ArrayList<>();
for(int i = queue.size();i>0;i--){
TreeNode p = queue.pollLast();
subRes.add(p.val);
if(p.right!=null){
queue.addFirst(p.right);
}
if(p.left!=null){
queue.addFirst(p.left);
}
}
res.add(subRes);
}
return res;
}
}
层序遍历+倒序
使用 Collections.reverse()函数
简单!
/**
* 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) {
Queue<TreeNode> queue = new LinkedList<>();
List<List<Integer>> res = new ArrayList<>();
if(root!=null){
queue.add(root);
}
while(!queue.isEmpty()){
List<Integer> subRes = new ArrayList<>();
for(int i=queue.size();i>0;i--){
TreeNode p = queue.poll();
subRes.add(p.val);
if(p.left!=null){
queue.add(p.left);
}
if(p.right!=null){
queue.add(p.right);
}
}
if(res.size()%2==1){
//偶数层,当前
Collections.reverse(subRes);
}
res.add(subRes);
}
return res;
}
}