「剑指Offer 32-Ⅰ.从上到下打印二叉树」

182 阅读3分钟

「剑指Offer 32-Ⅰ.从上到下打印二叉树」

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

题目描述(level 中等)

从上到下打印出二叉树的每个节点,同一层的节点按照从左到右的顺序打印。

示例
例如:

给定二叉树: [3,9,20,null,null,15,7],
    3
   / \
  9  20
    /  \
   15   7
   
返回:

[3,9,20,15,7]
初始TreeNode
public class TreeNode {
  int val;
  TreeNode left;
  TreeNode right;
  TreeNode(int x) {val = x;}
}
思路分析

题目比较简单,根据题目描述,要求从上到下打印整个二叉树,并且要求从左到右打印,提炼一下就是从左到右按层打印整个二叉树。明显的是对二叉树的广度优先搜索的考察。广度优先搜索Breadth-First SearchBFS,又称为宽度优先搜索,或者横向优先搜索,一种暴力的图形搜索算法,从根节点(root)开始从树的宽度遍历树的节点直到所有的节点均被访问到,跳出遍历。而BFS算法一般使用open-closed表来实现。说人话就是需要借助队列先入先出的特性来实现。思路总结如下:

  • 二叉树为空时的处理
  • 借助队列Queue将遍历到的节点存入到队列中,首先入队列的是根节点(root)
  • 循环♻️跳出条件为队列为空queue.isEmpty,取出队列中节点,同时将节点对应的值加入列表中存储(用于打印)
  • 从左到右,添加子节点(如果存在)
  • 处理列表中值val,返回数组
代码实现
class Solution {
  public int[] levelOrder(TreeNode root) {
    if (null == root) {
      return new int[0];
    }
    Queue<TreeNode> queue = new LinkedList<>();
    List<Integer> list = new ArrayList<>();
    queue.offer(root);

    while (!queue.isEmpty()) {
      TreeNode node = queue.poll();
      list.add(node.val);
      if (null != node.left) {
        queue.offer(node.left);
      }
      if (null != node.right) {
        queue.offer(node.right);
      }
    }

    int[] result = new int[list.size()];
    for (int i = 0; i < list.size(); i++) {
      result[i] = list.get(i);
    }
    return result;
  }
}
Tips
  • BFS一般会考虑到队列先入先出特性来实现,就像排序递增数组要第一反应考虑二分法一样,一种模版吧,但是也不能形成思维定势。只是多一种考虑的方向。
  • 对于队列接口Queue几个方法的注意使用区别
public interface Queue<E> extends Collection<E> {
  //Inserts the specified element into this queue if it is possible to do so immediately       	 //without violating capacity restrictions, returning true upon success and throwing an 		 	 	 //IllegalStateException if no space is currently available.
  //向队列添加元素时,如果添加成功返回true,如果队列满了,返回异常(IllegalStateException)
  boolean add(E e);
  
  //Inserts the specified element into this queue if it is possible to do so immediately 				//without violating capacity restrictions. When using a capacity-restricted queue, this 			//method is generally preferable to add, which can fail to insert an element only by throwing 	//an exception.
  //向队列添加元素时,如果添加成功返回true,如果队列满了,返回false
  boolean offer(E e);
  
  //Retrieves and removes the head of this queue. This method differs from poll only in that it 	//throws an exception if this queue is empty.
  //删除并返回队列头元素 如果队列为空,则抛出一个NoSuchElementException异常
  E remove();
  
  //Retrieves and removes the head of this queue, or returns null if this queue is empty.
	//Returns:the head of this queue, or null if this queue is empty
  //删除并返回队列头元素 如果队列为空,则返回null
  E poll();
  
  //Retrieves, but does not remove, the head of this queue. This method differs from peek only 	 //in that it throws an exception if this queue is empty.
  //Returns:the head of this queue
  //返回队列头元素,但是不删除元素,如果队列为空,则抛出一个NoSuchElementException异常
  E element();
  
  //Retrieves, but does not remove, the head of this queue, or returns null if this queue is 		//empty.
	//Returns:the head of this queue, or null if this queue is empty
  //返回队列头元素,但是不删除元素,如果队列为空,则返回null
  E peek();
}
  • 本例中采用的队列的子类为LinkedList,使用add()offer()方法效果是一样的,底层调用的均为add(),所以虽然Queue接口在使用时需要看子类的具体实现。需要了解这个几个方法的区别。
复杂度

时间复杂度O(N):需要访问二叉树所有节点

空间复杂度O(N):使用队列存储二叉树的节点,极端情况下使用N额外的内存空间

链接

从上到下打印二叉树