劍指 Offer 32 - III. 從上到下列印二叉樹 III
請實現一個函式按照之字形順序列印二叉樹,即第一行按照從左到右的順序列印,第二層按照從右到左的順序列印,第三行再按照從左到右的順序列印,其他行以此類推。
例如:
給定二叉樹: [3,9,20,null,null,15,7],
給定二叉樹: [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其層次遍歷結果:
[
[3],
[20,9],
[15,7]
]
提示:
- 節點總數 <= 1000
一、層序遍歷 + 雙端佇列
做題思路:與劍指 Offer 32 - I. 從上到下列印二叉樹 - RainsX - 部落格園 (cnblogs.com)和劍指 Offer 32 - II. 從上到下列印二叉樹 II - RainsX - 部落格園 (cnblogs.com)類似,只是在BFS迴圈的時候加入了判斷奇偶數的判定。當res.size()為偶數的時候,新增node.val的頭部,否則為尾部。
而且這道題可以與劍指 Offer 32 - I. 從上到下列印二叉樹 - RainsX - 部落格園 (cnblogs.com)、劍指 Offer 32 - II. 從上到下列印二叉樹 II - RainsX - 部落格園 (cnblogs.com)一起連著做,然後加深對BFS和輸的理解。
個人建議,可以試著把這個程式碼部分模組當做模板來熟悉,因為後續可能也有同樣的演算法題需要此類别範本。
/**
* 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> deque = new LinkedList<>();
List<List<Integer>> res = new ArrayList<List<Integer>>();
if(root != null) deque.add(root);
while(!deque.isEmpty()) {
LinkedList<Integer> tmp = new LinkedList<>();
for (int i = deque.size(); i>0; i--) {
TreeNode node = deque.poll();
if (res.size() % 2 == 0) tmp.addLast(node.val);
else tmp.addFirst(node.val);
if (node.left != null) deque.add(node.left);
if (node.right != null) deque.add(node.right);
}
res.add(tmp);
}
return res;
}
}
二、層序遍歷 + 雙端佇列(奇偶層邏輯分離)
這個做題思路是K神的思路,比起一開始簡化了很多步驟,這個梗容易看懂一些。
演算法流程如下:
BFS迴圈:
- 迴圈列印奇數/偶數層,當deque為空時候跳出
- 列印奇數層的時候,依次從左到右
- 列印偶數層的時候,依次從右到左
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
Deque<TreeNode> deque = new LinkedList<>();
List<List<Integer>> res = new ArrayList<>();
if(root != null) deque.add(root);
while(!deque.isEmpty()) {
// 列印奇數層
List<Integer> tmp = new ArrayList<>();
for(int i = deque.size(); i > 0; i--) {
// 從左向右列印
TreeNode node = deque.removeFirst();
tmp.add(node.val);
// 先左後右加入下層節點
if(node.left != null) deque.addLast(node.left);
if(node.right != null) deque.addLast(node.right);
}
res.add(tmp);
if(deque.isEmpty()) break; // 若為空則提前跳出
// 列印偶數層
tmp = new ArrayList<>();
for(int i = deque.size(); i > 0; i--) {
// 從右向左列印
TreeNode node = deque.removeLast();
tmp.add(node.val);
// 先右後左加入下層節點
if(node.right != null) deque.addFirst(node.right);
if(node.left != null) deque.addFirst(node.left);
}
res.add(tmp);
}
return res;
}
}
三、層序遍歷 + 倒序
這個倒序的思路,其實只要懂了判斷奇數/偶數層,就更容易什麼時候倒序。
/**
* 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> tmp = new ArrayList<>();
for (int i = queue.size(); i > 0; i--) {
TreeNode node = queue.poll();
tmp.add(node.val);
if (node.left != null) queue.add(node.left);
if (node.right != null) queue.add(node.right);
}
//當偶數層的時候就倒序,就跟方法一一樣改變順序即可
if (res.size() % 2 != 0) Collections.reverse(tmp);
res.add(tmp);
}
return res;
}
}
參考連結: