转载请注明出处:http://blog.csdn.net/crazy1235/article/details/51524241
出处:https://leetcode.com/problems/binary-tree-zigzag-level-order-traversal/
Given a binary tree, return the zigzag level order traversal of its nodes’ values. (ie, from left to right, then right to left for the next level and alternate between).
For example:
Given binary tree {3,9,20,#,#,15,7},
3
/ \
9 20
/ \
15 7
return its zigzag level order traversal as:
[
[3],
[20,9],
[15,7]
]
该题目与之前两题非常相似。
【LeetCode】102. Binary Tree Level Order Traversal 解题报告 是从顶层往下,从左往右的次序 遍历结点。
【LeetCode】107. Binary Tree Level Order Traversal II 解题报告 是从底层向上,从左往右的次序 遍历结点。
而该题目的意思是从顶层向下,”之字形” 顺序输出结点。(第一层从左向右,第二层从右向左,第三层从左向右……依次类推)。
第一种方案使用【102】题目中的非递归方法 进行修改。
主要就是记录当前结点所在的层级,或者当前层的结点的个数。
遇到需要反向的层的时候,调用Collections.reverse()方法或者使用LinkedList的addFirst()方法,还可以使用ArrayList的add(0, E)方法 (该方法效率不高,需要拷贝数组)。
/**
* 3ms
*
* beats 14.87% of java submissions
*
* @author jacksen
* @param root
* @return
*/
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> result = new ArrayList<List<Integer>>();
if (root == null) {
return result;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.add(root);
int i = queue.size(); // 记录每层的结点个数
boolean flag = false;
TreeNode tempNode = null;
List<Integer> singleLevel = new ArrayList<>();
while (!queue.isEmpty()) {
if (i == 0) {// 一层记录结束
//
if (flag) {
Collections.reverse(singleLevel);
}
result.add(singleLevel);
//
flag = !flag;
i = queue.size();
singleLevel = new ArrayList<>();
}
tempNode = queue.poll();
singleLevel.add(tempNode.val);
--i;
if (tempNode.left != null) {
queue.add(tempNode.left);
}
if (tempNode.right != null) {
queue.add(tempNode.right);
}
}
if (flag) {
Collections.reverse(singleLevel);
}
result.add(singleLevel);
return result;
}
/**
* 2ms
*
* beats 60.36% of java submissions
*
* @author jacksen
* @param root
* @return
*/
public List<List<Integer>> zigzagLevelOrder5(TreeNode root) {
List<List<Integer>> result = new ArrayList<List<Integer>>();
if (root == null) {
return result;
}
Queue<TreeNode> queue = new LinkedList<TreeNode>();
queue.add(root);
int i = queue.size(); // 记录每层的结点个数
boolean flag = true;
TreeNode tempNode = null;
LinkedList<Integer> singleLevel = new LinkedList<>();
while (!queue.isEmpty()) {
if (i == 0) {// 一层记录结束
//
result.add(singleLevel);
//
i = queue.size();
singleLevel = new LinkedList<>();
flag = !flag;
}
tempNode = queue.poll();
if (flag) {
singleLevel.add(tempNode.val);
} else {
singleLevel.addFirst(tempNode.val);
}
--i;
if (tempNode.left != null) {
queue.offer(tempNode.left);
}
if (tempNode.right != null) {
queue.offer(tempNode.right);
}
}
result.add(singleLevel);
return result;
}
通过递归方式。
将【102】题目中的递归方法 进行改造。
因为有层级这个变量,所以需要在每次递归时,判断 level % 2 是否为0 即可。
/**
* 递归方式
* 重要的是记录层级, 加上一个标识标识是否集合反向
*
* 1ms
* eats96.02% of java submissions
*
* @author jacksen
* @param root
* @return
*/
public List> zigzagLevelOrder2(TreeNode root) {
List> result = new ArrayList>();
// levelRecursion(root, result, 0, false);
levelRecursion2(root, result, 0);
return result;
}
/**
* 递归方法
*/
private void levelRecursion(TreeNode node, List> result,
int level, boolean flag) {
if (node == null) {
return;
}
if (result.size() < level + 1) {// 说明还需要添加一行
result.add(new LinkedList());
}
if (flag) {
((LinkedList) result.get(level)).addFirst(node.val);
} else {
result.get(level).add(node.val);
}
levelRecursion(node.left, result, level + 1, !flag);
levelRecursion(node.right, result, level + 1, !flag);
}
/**
* 可以直接通过level层级判断是否需要addFirst,不必要再添加额外的标识
*
* @param node
* @param result
* @param level
*/
private void levelRecursion2(TreeNode node, List> result,
int level) {
if (node == null) {
return;
}
if (result.size() < level + 1) {// 说明还需要添加一行
result.add(new LinkedList());
}
if (level % 2 != 0) {
((LinkedList) result.get(level)).addFirst(node.val);
} else {
result.get(level).add(node.val);
}
levelRecursion2(node.left, result, level + 1);
levelRecursion2(node.right, result, level + 1);
}
该方法效率最高
LeetCode 平台 Run Time 是 1ms
beats 96.02 % of java submissions.
该题目的Tags 显示了一个“Stack”标签。
说明可以通过栈的方式来做。
/**
* 用两个栈的方式
* 3ms
* beats 14.87% of java submissions
*
* @author jacksen
* @param node
* @return
*/
public List> zigzagLevelOrder3(TreeNode root) {
List> result = new ArrayList>();
if (root == null) {
return result;
}
Stack forwardStack = new Stack<>();
Stack retrorseStack = new Stack<>();
forwardStack.push(root);
TreeNode tempNode = null;
List singleList = new ArrayList<>();
while (!forwardStack.isEmpty() || !retrorseStack.isEmpty()) {
while (!forwardStack.isEmpty()) {
tempNode = forwardStack.pop();
singleList.add(tempNode.val);
if (tempNode.left != null) {
retrorseStack.push(tempNode.left);
}
if (tempNode.right != null) {
retrorseStack.push(tempNode.right);
}
}
if (!singleList.isEmpty()) {
result.add(singleList);
singleList = new ArrayList<>();
}
while (!retrorseStack.isEmpty()) {
tempNode = retrorseStack.pop();
singleList.add(tempNode.val);
if (tempNode.right != null) {
forwardStack.push(tempNode.right);
}
if (tempNode.left != null) {
forwardStack.push(tempNode.left);
}
}
if (!singleList.isEmpty()) {
result.add(singleList);
singleList = new ArrayList<>();
}
}
return result;
}
两个栈,一个从左向右遍历的层,一个存储从右向左遍历的层。
之字形层序输出,主要就是上一层从左向右,下一层从右向左。故而需要一个标志来进行区分。
从该题目的【Discuss】中看到一种使用Deque – 双端队列的解法。
/**
* deque 双端队列
* 3ms
* beats 14.87% of java submissions
*
* @author https://leetcode.com/discuss/89116/java-bfs-with-deque
*
* @param root
* @return
*/
public List> zigzagLevelOrder4(TreeNode root) {
List> result = new ArrayList>();
if (root == null) {
return result;
}
boolean flag = true;
TreeNode tempNode = null;
TreeNode lastNode = root;
List singleLevel = new ArrayList<>();
Deque deque = new LinkedList<>();
deque.offer(root);
while (!deque.isEmpty()) {
tempNode = flag ? deque.pollFirst() : deque.pollLast();
singleLevel.add(tempNode.val);
if (flag) {// left->right顺序添加到对尾
if (tempNode.left != null) {
deque.offerLast(tempNode.left);
}
if (tempNode.right != null) {
deque.offerLast(tempNode.right);
}
} else {
if (tempNode.right != null) {
deque.offerFirst(tempNode.right);
}
if (tempNode.left != null) {
deque.offerFirst(tempNode.left);
}
}
if (tempNode == lastNode) {
result.add(singleLevel);// 搞定一层
singleLevel = new ArrayList<>();
lastNode = flag ? deque.peekFirst() : deque.peekLast();
flag = !flag;
}
}
return result;
}
它的思想就是:
flag是true的时候,将节点从左向右添加到队尾。这样从队尾pollLast()的时候,顺序就是从右向左;
flag是false的时候,将节点从右向左添加到对头,这样从对头pollFirst()的时候,顺序就是从左向右。
【102】【107】【103】这些题目大体都是类似的。都是层序遍历输出二叉树。只不过顺序有差别而已。
大家可以举一反三。可以想想怎么从底层向上之字形层序遍历二叉树。
bingo~~