564,二叉树最大宽度
It isn't the big pleasures that count the most; it's making a great deal out of the little ones.
最重要的不是有大快乐,而是能充分享受小快乐。
问题描述
来源:LeetCode第662题
难度:中等
给定一个二叉树,编写一个函数来获取这个树的最大宽度。树的宽度是所有层中的最大宽度。这个二叉树与满二叉树(full binary tree)结构相同,但一些节点为空。
每一层的宽度被定义为两个端点(该层最左和最右的非空节点,两端点间的null节点也计入长度)之间的长度。
示例 1:
输入:
1
/ \
3 2
/ \ \
5 3 9
输出: 4
解释: 最大值出现在树的第 3 层,宽度为 4 (5,3,null,9)。
示例 2:
输入:
1
/
3
/ \
5 3
输出: 2
解释: 最大值出现在树的第 3 层,宽度为 2 (5,3)。
示例 3:
输入:
1
/ \
3 2
/
5
输出: 2
解释: 最大值出现在树的第 2 层,宽度为 2 (3,2)。
示例 4:
输入:
1
/ \
3 2
/ \
5 9
/ \
6 7
输出: 8
解释: 最大值出现在树的第 4 层,宽度为 8 (6,null,null,null,null,null,null,7)。
注意: 答案在32位有符号整数的表示范围内。
BFS解决
二叉树的最大宽度我们可以认为是从最左边到最右边的最大距离,假如是一棵满二叉树的话,每一层的最大距离就是最左边到最右边的节点数。因为二叉树不一定都是满二叉树,有可能像下面这样。
每一行从最左边到最右边我们很容易想到的就是二叉树的BFS遍历,他就是一层一层遍历的,关于二叉树的BFS不明白的可以看下下面的视频。
所以这题思路很容易想到,就是遍历每一层的时候计算这一层最左边节点到最右边节点的距离,大致代码如下
1public int widthOfBinaryTree(TreeNode root) {
2 if (root == null)
3 return 0;
4 //使用双端队列
5 Deque<TreeNode> queue = new LinkedList<>();
6 //把根节点加入到队列中
7 queue.offer(root);
8 //记录最大的宽度
9 int maxWide = 0;
10 while (!queue.isEmpty()) {
11 //当前层节点的数量
12 int levelCount = queue.size();
13 // int gap = 当前层最左边到最右边的距离
14 maxWide = Math.max(maxWide, gap);
15 //遍历当前层的所有节点,把他们的子节点在加入到队列中
16 for (int i = 0; i < levelCount; i++) {
17 TreeNode node = queue.poll();
18 //如果左子节点不为空,就把左子节点加入到队列中
19 if (node.left != null) {
20 queue.offer(node.left);
21 }
22 //如果右子节点不为空,就把右子节点加入到队列中
23 if (node.right != null) {
24 queue.offer(node.right);
25 }
26 }
27 }
28 return maxWide;
29}
他就是从上往下一层一层遍历的,遍历每一层的时候我们需要计算当前层的最大距离,保留最大的即可。这里关键是怎么计算当前层的最大距离。
我们可以这样来计算,把它想象成为一颗满二叉树,假如根节点是遍历的第1个节点,那么他的两个子节点分别是遍历的第2个和第3个节点。并且可以推算出如果一个节点是第n个遍历的,那么他的两个子节点分别是第n*2和n*2+1个遍历的,具体我们来画个图看一下
我们可以把这些值存到一个map中,也可以把它直接存到节点中,这里我们就把他存到节点中,在遍历每一层的时候用当前层最右边的值减去最左边的值+1就是当前层的最大距离,来看下最终代码。
1public int widthOfBinaryTree(TreeNode root) {
2 if (root == null)
3 return 0;
4 //使用双端队列
5 Deque<TreeNode> queue = new LinkedList<>();
6 //把根节点加入到队列中
7 queue.offer(root);
8 //根节点的值我们把它修改为1
9 root.val = 1;
10 //记录最大的宽度
11 int maxWide = 0;
12 while (!queue.isEmpty()) {
13 //当前层节点的数量
14 int levelCount = queue.size();
15 //当前层最左边节点的值
16 int left = queue.peekFirst().val;
17 //当前层最右边节点的值
18 int right = queue.peekLast().val;
19 //当前层的最大宽度就是right - left + 1,
20 //这里计算之后要保留最大的
21 maxWide = Math.max(maxWide, right - left + 1);
22 //遍历当前层的所有节点,把他们的子节点在加入到队列中
23 for (int i = 0; i < levelCount; i++) {
24 TreeNode node = queue.poll();
25 int position = node.val;
26 //如果左子节点不为空,就把左子节点加入到队列中
27 if (node.left != null) {
28 node.left.val = position * 2;
29 queue.offer(node.left);
30 }
31 //如果右子节点不为空,就把右子节点加入到队列中
32 if (node.right != null) {
33 node.right.val = position * 2 + 1;
34 queue.offer(node.right);
35 }
36 }
37 }
38 return maxWide;
39}
这里因为左边节点先入队,所以peekFirst()返回的就是当前层最左边的节点,右边节点是最后入队的,所以peekLast()返回的是当前层最右边的节点。
DFS解决
BFS是一层一层的打印,DFS是沿着一个分支一直走下去,当到达叶子节点的时候在往回走。所以这题解题思路也很简单,我们使用两个变量left和right
left变量记录每一层最左边的节点。
right变量记录每一层遍历过的最右边节点。
然后再每一层计算最右边到最左边的距离,也就是当前层的最大宽度,来看下代码
1//记录最大的宽度
2int maxWide = 0;
3
4public int widthOfBinaryTree(TreeNode root) {
5 dfs(root, 0, 1, new ArrayList<>(), new ArrayList<>());
6 return maxWide;
7}
8
9/**
10 * @param root
11 * @param level 遍历到第几层
12 * @param position 每个节点在满二叉树中的位置
13 * @param left 只记录最左边的节点,每层只记录一个
14 * @param right 只记录遍历过的最右边节点,每层只记录一个(这里是遍历过的,如果当前层有更右边的节点,
15 * 会把当前层的替换)
16 */
17public void dfs(TreeNode root, int level, int position, List<Integer> left, List<Integer> right) {
18 if (root == null)
19 return;
20 //首次到当前层,要把当前值分别加入到left和right中
21 if (left.size() == level) {
22 left.add(position);
23 right.add(position);
24 } else {//如果当前层已经遍历过,会替换掉
25 right.set(level, position);
26 }
27 //递归遍历下一层的左右子节点
28 dfs(root.left, level + 1, position << 1, left, right);
29 dfs(root.right, level + 1, position * 2 + 1, left, right);
30 //计算当前层的最大间距,保留最大值
31 maxWide = Math.max(maxWide, right.get(level) - left.get(level) + 1);
32}
●
●
●
●