vlambda博客
学习文章列表

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不明白的可以看下下面的视频。

564,二叉树最大宽度

所以题思路很容易想到,就是遍历每一层的时候计算这一层最左边节点到最右边节点的距离,大致代码如下

 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个遍历的,具体我们来画个图看一下

564,二叉树最大宽度

我们可以把这些值存到一个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, 01new 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}




你点的每个赞,我都认真当成了喜欢