zoukankan      html  css  js  c++  java
  • [LeetCode] 662. Maximum Width of Binary Tree 二叉树的最大宽度

    Given a binary tree, write a function to get the maximum width of the given tree. The width of a tree is the maximum width among all levels. The binary tree has the same structure as a full binary tree, but some nodes are null.

    The width of one level is defined as the length between the end-nodes (the leftmost and right most non-null nodes in the level, where the null nodes between the end-nodes are also counted into the length calculation.

    Example 1:

    Input: 
    
               1
             /   
            3     2
           /        
          5   3     9 
    
    Output: 4
    Explanation: The maximum width existing in the third level with the length 4 (5,3,null,9).
    

    Example 2:

    Input: 
    
              1
             /  
            3    
           /        
          5   3     
    
    Output: 2
    Explanation: The maximum width existing in the third level with the length 2 (5,3).
    

    Example 3:

    Input: 
    
              1
             / 
            3   2 
           /        
          5      
    
    Output: 2
    Explanation: The maximum width existing in the second level with the length 2 (3,2).
    

    Example 4:

    Input: 
    
              1
             / 
            3   2
           /       
          5       9 
         /         
        6           7
    Output: 8
    Explanation:The maximum width existing in the fourth level with the length 8 (6,null,null,null,null,null,null,7).
    
    
    

    Note: Answer will in the range of 32-bit signed integer.

    这道题让我们求二叉树的最大宽度,根据题目中的描述可知,这里的最大宽度不是满树的时候的最大宽度,如果是那样的话,肯定是最后一层的结点数最多。这里的最大宽度应该是两个存在的结点中间可容纳的总的结点个数,中间的结点可以为空。那么其实只要我们知道了每一层中最左边和最右边的结点的位置,我们就可以算出这一层的宽度了。所以这道题的关键就是要记录每一层中最左边结点的位置,我们知道对于一棵完美二叉树,如果根结点是深度1,那么每一层的结点数就是 2*n-1,那么每个结点的位置就是 [1, 2*n-1] 中的一个,假设某个结点的位置是i,那么其左右子结点的位置可以直接算出来,为 2*i 和 2*i+1,可以自行带例子检验。由于之前说过,我们需要保存每一层的最左结点的位置,那么我们使用一个数组 start,由于数组是从0开始的,我们就姑且认定根结点的深度为0,不影响结果。我们从根结点进入,深度为0,位置为1,进入递归函数。首先判断,如果当前结点为空,那么直接返回,然后判断如果当前深度大于 start 数组的长度,说明当前到了新的一层的最左结点,我们将当前位置存入 start 数组中。然后我们用 idx - start[h] + 1 来更新结果 res。这里 idx 是当前结点的位置,start[h] 是当前层最左结点的位置。然后对左右子结点分别调用递归函数,注意左右子结点的位置可以直接计算出来,代码参见评论区二楼。我们也可以让递归函数直接返回最大宽度了,但是解题思路没有啥区别,代码参见评论区三楼。这两种方法之前都能通过 OJ,直到后来加了一个很极端的 test case,使得二者都整型溢出了 Signed Integer Overflow,原因是这里每层都只有1个结点,而我们代码中坐标每次都要乘以2的,所以到32层以后就直接溢出了。为了避免溢出的问题,需要做些优化,就是要统计每层的结点数,若该层只有一个结点,那么该层结点的坐标值重置为1,这样就可以避免溢出了。所以 DFS 的解法就不能用了,只能用层序遍历,迭代的方法来写,这里使用了队列 queue 来辅助运算,queue 里存的是一个 pair,结点和其当前位置,在进入新一层的循环时,首先要判断该层是否只有1个结点,是的话重置结点坐标位置,再将首结点的位置保存出来当作最左位置,然后对于遍历到的结点,都更新右结点的位置,遍历一层的结点后来计算宽度更新结果 res,参见代码如下:

    class Solution {
    public:
        int widthOfBinaryTree(TreeNode* root) {
            if (!root) return 0;
            int res = 0;
            queue<pair<TreeNode*,int>> q;
            q.push({root, 1});
            while (!q.empty()) {
                if (q.size() == 1) q.front().second = 1;
                int left = q.front().second, right = left, n = q.size();
                for (int i = 0; i < n; ++i) {
                    auto t = q.front().first; 
                    right = q.front().second; q.pop();
                    if (t->left) q.push({t->left, right * 2});
                    if (t->right) q.push({t->right, right * 2 + 1});
                }
                res = max(res, right - left + 1);
            }
            return res;
        }
    };

    Github 同步地址:

    https://github.com/grandyang/leetcode/issues/662

    参考资料:

    https://leetcode.com/problems/maximum-width-of-binary-tree/

    https://leetcode.com/problems/maximum-width-of-binary-tree/discuss/327721/cpp-bfs-solution

    https://leetcode.com/problems/maximum-width-of-binary-tree/discuss/106654/javac-very-simple-dfs-solution

    https://leetcode.com/problems/maximum-width-of-binary-tree/discuss/106645/cjava-bfsdfs3liner-clean-code-with-explanation

    LeetCode All in One 题目讲解汇总(持续更新中...)

  • 相关阅读:
    List<T>的使用
    onclientclick和onclick区别
    IOS学习资料
    DataTable排序的一般方法
    jquery特效
    交叉表、行列转换和交叉查询经典
    sql截取查询
    DelPhi学习网站
    EasyDarwin开源云平台接入海康威视EasyCamera摄像机之快照获取与上传
    EasyDarwin开源云平台接入海康威视EasyCamera摄像机之快照获取与上传
  • 原文地址:https://www.cnblogs.com/grandyang/p/7538821.html
Copyright © 2011-2022 走看看