题目链接

题目描述:

给定一个二叉树,编写一个函数来获取这个树的最大宽度。树的宽度是所有层中的最大宽度。这个二叉树与满二叉树(full binary tree)结构相同,但一些节点为空。

每一层的宽度被定义为两个端点(该层最左和最右的非空节点,两端点间的null节点也计入长度)之间的长度。

示例1:
662二叉树最大宽度 - 图1
示例2:
662二叉树最大宽度 - 图2
示例3:
662二叉树最大宽度 - 图3
示例4:
662二叉树最大宽度 - 图4

BFS

  题目提示了我们满二叉树的结构,那让我们来回顾完全二叉树(满二叉树属于它的特殊情况)有什么结构特点?结合题目来考虑,要求我们求树的宽度而非深度,自然而然想到了可能会是层次遍历,也就是BFS。那么如何记录每一层的宽度呢?简单的level + 1显然不足以解决问题,这时候就要考虑完全二叉树中关于父节点与左右子结点索引的数值关系了,即父节点索引为i,左子结点索引为2 * i,右子结点索引为2 * i + 1。画图想一想,当前层的最右端索引 - 当前层的最左端索引 + 1就是当前层的宽度呗,剩下的不停地max找最大宽度。当然,也可以加一个list或vector专门记录每一层最左端索引(这就用上了level)。

代码

  1. class Solution {
  2. public:
  3. int widthOfBinaryTree(TreeNode* root) {
  4. if(!root)
  5. return 0;
  6. unsigned long long width = 0;
  7. queue< pair<TreeNode*,unsigned long long> > q;
  8. q.push(make_pair(root,1));
  9. while(!q.empty()){
  10. int size = q.size();
  11. unsigned long long l, r;
  12. for(int i = 0; i < size; i++){
  13. TreeNode* node = q.front().first;
  14. unsigned long long pos = q.front().second;
  15. q.pop();
  16. if(i == 0)
  17. l = pos;
  18. if(i == size - 1)
  19. r = pos;
  20. if(node->left)
  21. q.push(make_pair(node->left,pos * 2));
  22. if(node->right)
  23. q.push(make_pair(node->right,pos * 2 + 1));
  24. }
  25. width = max(width, r - l + 1);
  26. }
  27. return width;
  28. }
  29. };

DFS

  一般情况下,我们都是在求树的高度用到DFS,那么本题可不可以用呢?答案是可以的!刚才的最后一句话已经提醒我们了。其实道理想通,只不过和刚才利用队列每一层一结算不同,因为递归的特点,我们要记录每一层最左端的索引,然后通过level定位当前结点所属层并与所属层的最左端索引相减并加1,不断max获取当前最大宽度即可。
  那么计算机是怎么知道当前结点是否是当前层的最左端结点呢?可以会想先序遍历框架,当我们第一次经过结点是就进行visit,这就为我们解决该需求提供了前提。我们设一个记录最左端点索引的容器recordLevel,显然层数与容器的size大小相等,那么经过结点就判断当前层是否>容器大小,如果大于,显然这是第一次到达该层次,刚次已经提到了先序遍历根左右嘛,可以断定这就是当前层的最左端结点,记录即可。还有对当前结点的操作就是计算最大宽度啦,剩下的交给递归~

代码

  1. class Solution {
  2. public:
  3. int widthOfBinaryTree(TreeNode* root) {
  4. if(!root)
  5. return 0;
  6. helper(root, 1, 1);
  7. return width;
  8. }
  9. private:
  10. unsigned long long width = 0;
  11. vector<unsigned long long> recordLevel;
  12. void helper(TreeNode* root, unsigned long long pos, int level){
  13. if(!root)
  14. return;
  15. if(level > recordLevel.size())
  16. recordLevel.push_back(pos);
  17. width = max(width, pos - recordLevel[level - 1] + 1);
  18. if(root->left)
  19. helper(root->left, pos * 2, level + 1);
  20. if(root->right)
  21. helper(root->right, pos * 2 + 1, level + 1);
  22. return;
  23. }
  24. };

关于测试用例

  如果我们用int或者long long记录最大宽度width和索引pos,无论是DFS还是BFS,我们很可能倒在测试用例107,别问我是怎么知道的~整数溢出嘛

Line 35: Char 54: runtime error: signed integer overflow: 2147483647 * 2 cannot be represented in type 'int' (solution.cpp)

  怎么解决呢,一个比较简单的方式就是将宽度和索引的变量类型设为unsigned long long即可通过。

如果有错误或者不严谨的地方,请务必给予指正,十分感谢。