【注】该题解转载自LeetCode 102题官方题解
我们可以用广度优先搜索解决这个问题。
我们可以想到最朴素的方法是用一个二元组 (node, level) 来表示状态,它表示某个节点和它所在的层数,每个新进队列的节点的 level 值都是父亲节点的 level 值加一。最后根据每个点的 level 对点进行分类,分类的时候我们可以利用哈希表,维护一个以 level 为键,对应节点值组成的数组为值,广度优先搜索结束以后按键 level 从小到大取出所有值,组成答案返回即可。
考虑如何优化空间开销:如何不用哈希映射,并且只用一个变量 node 表示状态,实现这个功能呢?
我们可以用一种巧妙的方法修改 BFS:
- 首先根元素入队
- 当队列不为空的时候
- 求当前队列的长度
$s_i$ - 依次从队列中取
$s_i$ 个元素进行拓展,然后进入下一次迭代
- 求当前队列的长度
它和 BFS 的区别在于 BFS 每次只取一个元素拓展,而这里每次取
为什么这么做是对的呢?我们观察这个算法,可以归纳出这样的循环不变式:第
证明它的三条性质(你也可以把它理解成数学归纳法):
初始化:$i=1$的时候,队列里面只有 root,是唯一的层数为 1 的元素,因为只有一个元素,所以也显然满足「从左向右排列」;
保持:如果
/**
* 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) {
List<List<Integer>> res = new ArrayList<>();
LinkedList<TreeNode> queue = new LinkedList<>();
if (root != null)
queue.offer(root);
while (!queue.isEmpty()) {
int len = queue.size();
TreeNode node;
List<Integer> levelNodes = new ArrayList<>();
for (int i = 0; i < len; i++) {
node = queue.poll();
if (node != null) {
levelNodes.add(node.val);
if (node.left != null)
queue.offer(node.left);
if (node.right != null)
queue.offer(node.right);
}
}
res.add(levelNodes);
}
return res;
}
}
复杂度分析
记树上所有节点的个数为
![image-20210126104222917](/Users/caozhengcheng/Documents/knowledge base/pic/image-20210126104222917.png)
/**
* 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) {
List<List<Integer>> res = new ArrayList<>();
dfs(0, root, res);
return res;
}
public void dfs(int index, TreeNode root, List<List<Integer>> res) {
if (root == null)
return;
if (res.size() <= index)
res.add(new ArrayList<Integer>());
res.get(index).add(root.val);
dfs(index+1, root.left, res);
dfs(index+1, root.right, res);
}
}