0%

leetcode-102

102. 二叉树的层序遍历

给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。

示例:
二叉树:[3,9,20,null,null,15,7],

3

/
9 20
/
15 7
返回其层序遍历结果:

[
[3],
[9,20],
[15,7]
]

方法一:广度优先搜索

思路和算法

我们可以想到最朴素的方法是用一个二元组 (node, level) 来表示状态,它表示某个节点和它所在的层数,每个新进队列的节点的 level 值都是父亲节点的 level 值加一。最后根据每个点的 level 对点进行分类,分类的时候我们可以利用哈希表,维护一个以 level 为键,对应节点值组成的数组为值,广度优先搜索结束以后按键 level 从小到大取出所有值,组成答案返回即可。

考虑如何优化空间开销:如何不用哈希映射,并且只用一个变量 node 表示状态,实现这个功能呢?

我们可以用一种巧妙的方法修改广度优先搜索:

  • 首先根元素入队
  • 当队列不为空的时候
    • 求当前队列的长度 si
    • 依次从队列中取 si 个元素进行拓展,然后进入下一次迭代

它和普通广度优先搜索的区别在于,普通广度优先搜索每次只取一个元素拓展,而这里每次取si 个元素。在上述过程中的第 i 次迭代就得到了二叉树的第 i 层的 si

个元素。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public List<List<Integer>> ans = new ArrayList<>();
public List<List<Integer>> levelOrder(TreeNode root) {
if (root == null) {
return new ArrayList<>();
}

List<List<Integer>> res = new ArrayList<>();
Queue<TreeNode> deq = new LinkedList<>();
deq.offer(root);

while (!deq.isEmpty()) {
int length = deq.size();
List<Integer> level = new ArrayList<>();
for (int i = 0; i < length; i++) {
TreeNode node = deq.poll();
assert node != null;
level.add(node.val);
if (node.left != null) {
deq.offer(node.left);
}
if (node.right != null) {
deq.offer(node.right);
}
}
res.add(level);
}
return res;
}
}

复杂度分析

记树上所有节点的个数为 n。

时间复杂度:每个点进队出队各一次,故渐进时间复杂度为 O(n)。

空间复杂度:队列中元素的个数不超过 n 个,故渐进空间复杂度为 O(n)。

方法二:深度优先搜索

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Solution2 {
List<List<Integer>> ans = new ArrayList<>();
public List<List<Integer>> levelOrder(TreeNode root) {
helper(root, 0);
return ans;
}

private void helper(TreeNode root, int level) {
if (root == null) {
return;
}
if (ans.size() == level) {
ans.add(new ArrayList<>());
}
ans.get(level).add(root.val);
helper(root.left, level + 1);
helper(root.right, level + 1);
}
}