「剑指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 Search即BFS,又称为宽度优先搜索,或者横向优先搜索,一种暴力的图形搜索算法,从根节点(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额外的内存空间