请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。
例如:
给定二叉树: [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其层次遍历结果:
[
[3],
[20,9],
[15,7]
]
是对二叉树层序遍历进一步考察,结合前面两题,分别考察了二叉树的简单按层打印,整体返回结果,层序遍历,单层结果返回。而本题是对按层返回结果的同时作奇偶变换。之前分析过,二叉树层序遍历BFS广度优先搜索,一般首先能想到的是使用队列的先入先出特性来实现。分析此题,与32-II的唯一区别就是对奇偶的层数的不同,奇数层从左到右打印,偶数层从右到左打印。既然结果是一个List,只需要遍历List根据下标index的奇偶性对子集合List作反转即可。但是如果真在面试过程中遇到了这题,建议还是写两种解法,依个人愚见,本题更倾向于对双端队列的考察。结果反转思路总结:
temp list
进行反转「剑指Offer 32-Ⅰ.从上到下打印二叉树」
「剑指Offer 32-II. 从上到下打印二叉树 II」
除了对结果根据奇偶性进行反转,还可以通过双端队列对临时结果list
进行预先处理,思想其实是一样的,当被处理的行数为偶数时(要求从右到左打印)将数字添加到队列头部,当被处理的行数为奇数时,将数字添加到队列尾部。
list
思路总结如下:
以示例中例子为例
3
/ \
9 20
/ \
15 7
List<List<Integer>> result = new ArrayList<>();
LinkedList<Integer> temp = new LinkedList<>();
当[3]被添加到result中以后,此时result的size大小为1,
下一行为偶数([9,20]),需要被添加到头部,但是此时层序遍历的方向是不变的;
依然是从9到20。当9被添加到头部(addFirst),则 temp = [9],
接着遍历20,然后再添加到头部的到temp = [20,9],
对数组进行了“反转”。打印总结果时得到的就是反转后的内容。
temp list
根据奇偶性对其反转class Solution {
if (null == root) {
return new ArrayList<>();
}
Queue<TreeNode> queue = new LinkedList<>();
List<List<Integer>> result = new ArrayList<>();
queue.offer(root);
while (!queue.isEmpty()) {
List<Integer> temp = new ArrayList<>();
for (int i = queue.size(); i > 0; i--) {
TreeNode node = queue.poll();
if (null != node) {
temp.add(node.val);
if (null != node.left) {
queue.offer(node.left);
}
if (null != node.right) {
queue.offer(node.right);
}
}
}
//根据奇偶性对集合进行反转
if (result.size() % 2 == 1) {
Collections.reverse(temp);
}
result.add(temp);
}
return result;
}
这里对临时集合temp list
反转判断的是当前总集合list
的大小的奇偶性,如果当前大小size
为偶数那么待添加的子List则不需要反转(从右到左)
,反之亦然。
class Solution {
if (null == root) {
return new ArrayList<>();
}
Queue<TreeNode> queue = new LinkedList<>();
List<List<Integer>> result = new ArrayList<>();
queue.offer(root);
while (!queue.isEmpty()) {
LinkedList<Integer> temp = new LinkedList<>();
for (int i = queue.size(); i > 0; i--) {
TreeNode node = queue.poll();
if (null != node) {
/*偶数层加入队列的头部*/
if (result.size() % 2 == 0) {
temp.addLast(node.val);
} else {
temp.addFirst(node.val);
}
if (null != node.left) {
queue.offer(node.left);
}
if (null != node.right) {
queue.offer(node.right);
}
}
}
result.add(temp);
}
return result;
}
if (result.size() % 2 == 0)
判断的是当前总结果result的大小size,
如果当前size为偶数那么待添加的下一层为奇数,反之亦然
时间复杂度O(N):层序遍历需要遍历每一个节点,与节点的个数N成线性
空间复杂度O(N):额外使用队列,空间复杂度与节点个数相关
剑指 Offer 32-III. 从上到下打印二叉树III