二叉树在每一层的宽度,定义为这一层中,最左侧节点到最右侧节点之间的长度(中间的null
节点也被计算在内)。二叉树的最大宽度,就是每一层的宽度中的最大值。
根据题目描述来看,最直观的想法就是BFS层序遍历。遍历每一层,求每一层的宽度,然后取一个max
。关键是每一层的宽度怎么求?由于中间允许有null
节点。想了一会儿后,发现用数组模拟二叉树时,节点在数组中都有一个下标,这个下标,可以用来解这道题。
在用数组模拟二叉树时,每个节点在数组中会有一个下标(编号)。当是满二叉树时,我们会按照层序遍历的顺序,依次给节点编号。
若根节点编号从1
开始,则对于编号为x
的节点,其左儿子的编号为2 * x
,其右儿子的编号为2 * x + 1
。
(根节点编号从1
开始,计算比较方便;若根节点编号从0
开始,则左儿子为2 * x + 1
,右儿子为2 * x + 2
)。
那么,将题目中这棵树看成满二叉树(为空的节点也认为是有节点),我们对每个节点进行编号。求某一层的宽度,只需要用该层最后一个节点的编号,减去该层第一个节点的编号,即可算出中间的长度。
对节点增加一个编号,可以通过创建一个新的数据结构来做,也可以用Map
来保存每个节点对应的编号,也可以用Queue
来对编号进行存储(因为每一次都是处理一层的节点),下面选择用Queue
来存储节点编号
代码如下
class Solution {
public int widthOfBinaryTree(TreeNode root) {
if (root == null) return 0;
// 需要计算每一层的宽度, 并从中取最大值, 用BFS来做
Queue<TreeNode> queue = new LinkedList<>();
Queue<Integer> indexQueue = new LinkedList<>();
int ans = 1;
queue.offer(root);
indexQueue.offer(1);
while (!queue.isEmpty()) {
// 将这一层的拿出来
int size = queue.size();
int left = 0; // 该层第一个节点的下标
int right = 0; // 该层最后一个节点的下标
for (int i = 0; i < size; i++) {
TreeNode node = queue.poll();
int index = indexQueue.poll();
if (node.left != null) {
queue.offer(node.left);
indexQueue.offer(2 * index);
}
if (node.right != null) {
queue.offer(node.right);
indexQueue.offer(2 * index + 1);
}
if (i == 0) left = index;
if (i == size - 1) right = index;
}
ans = Math.max(ans, right - left + 1);
}
return ans;
}
}
这道题也可以用DFS来做,不过DFS的思路没有BFS直观。
用DFS来做,我们采用前序遍历,因为用前序遍历时,每一层中的最左侧的节点,是这一层所有节点中,第一个被访问到的。而我们需要每一层的第一个节点,这样的信息。只要获取到每一层最左侧节点的下标。
在后续的遍历中,当访问到某一个节点时,只需要用该节点的下标,减去当前层的最左侧节点的下标,得到一个长度,用这个长度去更新答案即可,因为会遍历所有的节点,那么这个答案总是会被当前层更大的宽度所更新,最后得到的就是所有层中的最大宽度。
我们需要一个Map
,来记录每一层最左侧节点的下标
class Solution {
int ans = 0;
Map<Integer, Integer> leftIndex = new HashMap<>();
public int widthOfBinaryTree(TreeNode root) {
dfs(root, 0, 1);
return ans;
}
// 访问节点node, 该节点所在的层为 depth, 其下标为 pos
public void dfs(TreeNode node, int depth, int pos) {
if (node == null) return;
// 采用前序遍历, 则每一层的最左侧节点, 一定是最先被访问到的
// 第一次被访问到的话, 则记录该层最左侧节点下标的信息
if (!leftIndex.containsKey(depth)) leftIndex.put(depth, pos);
ans = Math.max(ans, pos - leftIndex.get(depth) + 1);
dfs(node.left, depth + 1, 2 * pos);
dfs(node.right, depth + 1, 2 * pos + 1);
}
}