一、层次遍历思想,迭代法
根据题目名,最先想到的是采用层次遍历的方法,但是一分析发现,默认的队列记录法不好用了。
经过画图分析,在开队列迭代层序遍历思想的基础上,开两个堆栈,分别记录奇数层和偶数层的节点。
奇数层从右往左压栈,出栈时的循序,是从左往右的,把其子节点压到偶数层堆栈,偶数层堆栈出栈的顺序就符合图示要求,即从右往左的。如此递归循环。
- 怎么记录现在在哪一层?
每一轮,完成一层的遍历后,levels++,levels指示所在层数。每一轮,堆栈中只包含该层的节点,通过读取堆栈size(),控制for循环次数为size次实现。
运行结果
执行结果:通过
执行用时:2 ms
代码与注释
class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
// 先入后出:用堆栈
Stack<TreeNode> stack1 = new Stack<>(); // 奇数层堆栈
Stack<TreeNode> stack2 = new Stack<>(); // 偶数层堆栈
List<List<Integer>> ans = new LinkedList<List<Integer>>();
if (root == null) return ans;
int levels = 0;
stack1.push(root);
while (!stack1.isEmpty() || !stack2.isEmpty())
{
levels ++;
LinkedList<Integer> tmp = new LinkedList<>();
// 奇数层:从左到右
if (levels % 2 == 1)
{
int len = stack1.size();
for (int i = 0; i < len; i++)
{
root = stack1.pop();
tmp.add(root.val);
if (root.left != null) stack2.push(root.left);
if (root.right != null) stack2.push(root.right);
}
}
// 偶数层:从右往左
else
{
int len = stack2.size();
for (int i = 0; i < len; i++)
{
root = stack2.pop();
tmp.add(root.val);
if (root.right != null) stack1.push(root.right);
if (root.left != null) stack1.push(root.left);
}
}
ans.add(tmp);
}
return ans;
}
}
二、DFS思想,递归法
传统的递归法也可以实现要求的层次遍历。
小技巧:
1.利用add()函数特性,在特定位置持续写入元素,相当于将一串数据反序,即add(0, root.val)操作。简单又好用。
2.判断奇数偶数不仅可以用levels % 2 == 0,还可以用位运算levels & 1 == 0。
- 何时添加ans新层?
条件:levels == ans.size(),获取ans创建的行数,如果跟现在的层数相同,则建立新行。
运行结果
执行结果:通过
执行用时:1 ms, 在所有 Java 提交中击败了98.78%的用户
内存消耗:36 MB, 在所有 Java 提交中击败了72.60%的用户
代码与注释
class Solution {
public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
List<List<Integer>> ans = new ArrayList<>();
dfs(root, 0, ans);
return ans;
}
private void dfs(TreeNode root, int levels, List<List<Integer>> ans)
{
if (root == null) return;
if (levels == ans.size()) ans.add(new ArrayList<Integer>());
// 奇数行
if (levels % 2 == 0) ans.get(levels).add(root.val);
// 偶数行,利用add(),新数会把老数往后挤,效果就是反序
else ans.get(levels).add(0, root.val);
dfs(root.left, levels + 1, ans);
dfs(root.right, levels + 1, ans);
}
}
总结
- 采用二叉树常见递归方法,在此基础上添加约束条件。
- 给出添加结果List新行条件为:与当前层数相同,防止递归添加过多行。
- 进入下次递归前,添加val到结果列表。
- 区分奇偶行,将val添加到该层对应列表的头或尾。