leetcode每日一题【二叉树最大宽度】2022/8/26

662. 二叉树最大宽度【中】

思路1:广度优先+完全二叉树序号


直接思路肯定是从层序遍历开始,首先想到是除了层序遍历需要的队列,额外维护一个队列,用于存放层序遍历时node在完全二叉树对应的编号,这个队列存放编号和层序遍历的队列存放的节点是一一对应的,且操作保持一致(一起pop,一起push)。然后每一层遍历时,就将队列的最后一个编号和第1个编号相减+1就是这一层的宽度,如上,最大宽度是4,因为7-4+1。最后保留一个最大宽度即可。

代码:

//t:O(N) s:O(N) 和广度优先一致
class Solution {
public:
    int widthOfBinaryTree(TreeNode* root) {
        if(!root) return 0;
        // 层序遍历所需队列
        queue<TreeNode *> q;
        // 完全二叉树编号队列
        queue<int> number;
        
        q.push(root);
        number.push(1);
       
        int maxwidth =0;
        int right=0,left=0;
        // 层序遍历
        while(q.size()!=0){
            int len = q.size();
            for(int i =0 ;i<len;i++){
                TreeNode* node = q.front();
                int parentnum = number.front();
                if(node->left){
                    q.push(node->left);
                    number.push(parentnum*2); // 左孩子编号
                }
                if(node->right){
                    q.push(node->right);
                    number.push(parentnum*2+1); // 右孩子编号
                }
                if(i==0) left =  parentnum;
                if(i==len-1) right =  parentnum;
                
                number.pop();
                q.pop();
            }
            if((right-left+1)>maxwidth) maxwidth = right-left+1;
        }
        return maxwidth;
    }
};

然而试例给了一棵非常高的树,使得完全二叉树编号超出了32位int(题目告知)的范围2147483647。
在这里插入图片描述
看了一下官方的答案,用了unsigned long long(64位)解决问题,还使用了很多技巧,最后简化一下代码:

class Solution {
public:
    int widthOfBinaryTree(TreeNode* root) {
    	//pair是将2个数据组合成一组数据的一种数据类型
    	//使用vector而非queue完成
        vector<pair<TreeNode*,unsigned long long>> node_arr; 
        //emplace_back比push_back效率更高(实际上提交并没有展现出来)
        node_arr.emplace_back(root,1L);
        unsigned long long width=1,max=1; 
        // 开始广度优先
        while(!node_arr.empty()){
        	// 每次都生成一个tmp,用于存放下一层的数据 
            vector<pair<TreeNode*,unsigned long long>> tmp;
            for(auto &[node,index]:node_arr){
                if(node->left) tmp.emplace_back(node->left,index*2);
                if(node->right) tmp.emplace_back(node->right,index*2+1);
            }
            //计算当前层数据,这里很重要,很容易写成tmp.back().second - tmp[0].second+1
            //而当遍历到最后一层的时候,再计算下一层的宽会是空的,所以遍历一层,计算一层宽
            width = node_arr.back().second - node_arr[0].second+1; 
            if(width>max) max = width;
            // 直观理解:掏空tmp,将tmp的值交给node_arr进行数据拷贝
            node_arr = move(tmp);
        }
        return max;
    }
};

思路2 深度优先

瞥见了有深度优先的方法,研究了一下,感觉也很有意思。
同样利用了完全二叉树的编号,使用了三个很重要的变量,depth二叉树深度,id即二叉树编号,以及哈希表level。level记录所有层最左边结点的编号。每次递归,如果level中没有key为depth的值,说明到了新的一层,且访问的是该层最左端(深度优先遍历的性质),记录id值;如果有,那么计算当前节点id-level[depth]+1就是当前节点距离当前层最左边结点的宽度,不断递归,返回最大宽度。

// s:O(n)递归深度 t:O(n)遍历所有点
using ULL = unsigned long long;
class Solution {
public:
    unordered_map<int,int> level; //没有记录节点,不算入空间复杂度
    int widthOfBinaryTree(TreeNode* root) {
        return dfs(root,0,1ULL);
    }

    int dfs(TreeNode* node, int depth,ULL id){
        if(!node) return 0; 
        if(!level.count(depth)) level[depth] = id; //如果没访问过,就是最左边的id
        int width = id-level[depth]+1; //用当前节点id减去最左边节点id
        int left = dfs(node->left,depth+1,id*2); // 去左孩子看看
        int right = dfs(node->right,depth+1,id*2+1); // 去右孩子看看
        return max({width,left,right}); // max的技巧,当比较三个的时候加个{}
    }
};
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值