树/二叉树的层序遍历 掌握这个方法轻松解决16道LeetCode题

WechatIMG56.png
我们知道树/图的深度优先搜索使用递归可以很简单的实现,但树的广度优先搜索是依赖于队列先见先出的特性来实现的,不方便使用递归实现。今天我们来看看树的层序遍历方法,掌握了这个方法,广度优先搜索的大部分题都可以轻松解决了。

1. 二叉树的层序遍历

剑指 Offer 32 - I. 从上到下打印二叉树

先看这个最简单的层序遍历,只需要按广度优先的顺序一个一个地输出节点值就可以了
要点:

  • 头结点入队
  • 队列不为空时不断出队,出队节点值加入结果
  • 将出队节点的左右子节点入队
  • 重复以上直到队列为空
vector<int> levelOrder(TreeNode* root) {
    vector<int> res;
    if(!root) return res;
    queue<TreeNode*> que;
    que.push(root);
    while(!que.empty()){
        auto node = que.front();
        que.pop();
        res.push_back(node->val);
        if(node->left) que.push(node->left);
        if(node->right) que.push(node->right);
    }
    return res;
}

102. 二叉树的层序遍历
剑指 Offer 32 - II. 从上到下打印二叉树 II
这个是一个稍复杂点的层序遍历,遍历过程还跟上面一题一样,只是要求输出结果按层存储。这就要求在队列中标记每一层的边界

  1. 第一种解法是每一层入队完成后加入空节点做哨兵。
    要点:
  • 头结点入队后再入队一个空节点(因为第一层只有一个空节点)
  • 出队时只要弹出的节点不是空节点说明没到层尾,继续遍历和入度左右子节点
  • 如果出队弹出的节点是空节点并且该层节点不为空(最后一一个空节点出队会时该层节点数为空),说明到了层尾,此时将该层结果加入结果集并清空该层结果,继续入队空节点
  • 队列空遍历结束
vector<vector<int>> levelOrder(TreeNode* root) {
    vector<vector<int>> res;
    if(!root) return res;
    queue<TreeNode*> que;
    que.push(root);
    que.push(nullptr);
    vector<int> temp;
    while(!que.empty()){
        auto node = que.front();
        que.pop();
        if(node){
            temp.push_back(node->val);
            if(node->left) que.push(node->left);
            if(node->right) que.push(node->right);
        }else if(!temp.empty()){
            res.push_back(temp);
            temp.clear();
            que.push(nullptr);
        }
    }
    return res;
}
  1. 第二种解法 通过记录未出队元素数目标记一层遍历结束
    要点:
  • 头结点入队
  • 循环遍历队列时先记录未遍历节点数目(这就是当前层节点数)
  • 循环递减当前层节点数直到为0,该层节点出队、加入结果集、左右子节点入队
  • 一层遍历完之后结果加入结果集,该层结果清空
  • 队列为空时遍历结束

时间复杂度也是O(n), 因为少加入了一些哨兵节点所以性能和内存消耗比第一种方法更好。

vector<vector<int>> levelOrder(TreeNode* root) {
    vector<vector<int>> res;
    if(!root) return res;
    queue<TreeNode*> que;
    que.push(root);
    vector<int> temp;
    while(!que.empty()){
        auto size = que.size();
        while(size--){
            auto node = que.front();
            que.pop();
            temp.push_back(node->val);
            if(node->left) que.push(node->left);
            if(node->right) que.push(node->right);
        }
        res.push_back(temp);
        temp.clear();
    }
    return res;
}

下面就是层序遍历的各种变种了,套路都是一样的,只有局部有小的调整。

2. 二叉树自底向上层序遍历

107. 二叉树的层序遍历 II
和上题一样,只需要最后将结果集逆置一下就可以了

vector<vector<int>> levelOrderBottom(TreeNode* root) {
    vector<vector<int>> res;
    if(root == nullptr)
        return res;
    queue<TreeNode*> que;
    que.push(root);
    vector<int> temp;
    while(!que.empty()){
        auto size = que.size();
        while(size--){
            auto node = que.front();
            que.pop();
            temp.push_back(node->val);
            if(node->left) que.push(node->left);
            if(node->right) que.push(node->right);
        }
        res.push_back(temp);
        temp.clear();
    }
    reverse(res.begin(), res.end());
    return res;
}

3. 二叉树锯齿形层序遍历

103. 二叉树的锯齿形层序遍历
与普通层序遍历的差异仅在于增加标志一层正序输出一层逆序输出

    vector<vector<int>> res;
    if(!root) return res;
    queue<TreeNode*> que;
    que.push(root);
    vector<int> temp;
    bool change = false;
    while(!que.empty()){
        auto size = que.size();
        while(size--){
            auto node = que.front();
            que.pop();
            temp.push_back(node->val);
            if(node->left) que.push(node->left);
            if(node->right) que.push(node->right);
        }
        if(change) reverse(temp.begin(), temp.end());
        change = !change;
        res.push_back(temp);
        temp.clear();
    }
    return res;
}

4. 多叉树的层序遍历

429. N 叉树的层序遍历
与二叉树的层序遍历基本一致

vector<vector<int>> levelOrder(Node* root) {
    vector<vector<int>> res;
    if(!root) return res;
    queue<Node*> que;
    que.push(root);
    vector<int> temp;
    while(!que.empty()){
        auto size = que.size();
        while(size--){
            auto node = que.front();
            que.pop();
            temp.push_back(node->val);
            for(const auto c : node->children)
                if(c) que.push(c);
        }
        res.push_back(temp);
        temp.clear();
    }
    return res;
}

5. 二叉树的层平均值

637. 二叉树的层平均值

vector<double> averageOfLevels(TreeNode* root) {
    vector<double> res;
    if(!root) return res;
    queue<TreeNode*> que;
    que.push(root);
    while(!que.empty()){
        auto size = que.size();
        auto index = size;
        double value{};
        while(index--){
            auto node = que.front();
            que.pop();
            value += node->val;
            if(node->left) que.push(node->left);
            if(node->right) que.push(node->right);
        }
        res.push_back(value/size);
    }
    return res;
}

6. 二叉树的层最大值

515. 在每个树行中找最大值
剑指 Offer II 044. 二叉树每层的最大值

vector<int> largestValues(TreeNode* root) {
    vector<int> res;
    if(!root) return res;
    queue<TreeNode*> que;
    que.push(root);
    while(!que.empty()){
        auto size = que.size();
        int value = que.front()->val;
        while(size--){
            auto node = que.front();
            que.pop();
            value = max(value, node->val);
            if(node->left) que.push(node->left);
            if(node->right) que.push(node->right);
        }
        res.push_back(value);
    }
    return res;
}

7. 二叉树最底层最左边的值

513. 找树左下角的值
剑指 Offer II 045. 二叉树最底层最左边的值

int findBottomLeftValue(TreeNode* root) {
    queue<TreeNode*> que;
    que.push(root);
    int value = root->val;
    while(!que.empty()){
        value = que.front()->val;
        auto size = que.size();
        while(size--){
            auto node = que.front();
            que.pop();
            if(node->left) que.push(node->left);
            if(node->right) que.push(node->right);
        }
    }
    return value;
}

8. 二叉树的右侧视图

199. 二叉树的右视图
剑指 Offer II 046. 二叉树的右侧视图

vector<int> rightSideView(TreeNode* root) {
    vector<int> res;
    if(!root) return res;
    queue<TreeNode*> que;
    que.push(root);
    while(!que.empty()){
        auto size = que.size();
        auto index = size;
        int value{};
        while(index--){
            auto node = que.front();
            que.pop();
            value = node->val;
            if(node->left) que.push(node->left);
            if(node->right) que.push(node->right);
        }
        res.push_back(value);
    }
    return res;
}

9. 二叉树中插入一层

623. 在二叉树中增加一行

TreeNode* addOneRow(TreeNode* root, int val, int depth) {
    if(!root || depth < 1) return nullptr;
    if(depth == 1){
        auto head = new TreeNode(val, root, nullptr);
        return head;
    }
    queue<TreeNode*> que;
    que.push(root);
    int depthIndex = 1;
    while(!que.empty()){
        auto size = que.size();
        while(size--){
            auto node = que.front();
            que.pop();
            if(depthIndex == depth-1){
                node->left = new TreeNode(val, node->left, nullptr);
                node->right = new TreeNode(val, nullptr, node->right);
            }else{
                if(node->left) que.push(node->left);
                if(node->right) que.push(node->right);
            }
        }
        depthIndex++;
    }
    return root;
}

10. 二叉树层内最大元素和

1161. 最大层内元素和

int maxLevelSum(TreeNode* root) {
    queue<TreeNode*> que;
    que.push(root);
    int maxSum = root->val;
    int level = 1;
    int maxLevel = level;
    while(!que.empty()){
        auto size = que.size();
        int value{};
        while(size--){
            auto node = que.front();
            que.pop();
            value += node->val;
            if(node->left) que.push(node->left);
            if(node->right) que.push(node->right);
        }
        if(value > maxSum) {
            maxSum = value;
            maxLevel = level;
        }
        level++;
    }
    return maxLevel;
}

11. 二叉树层数最深叶子节点的和

1302. 层数最深叶子节点的和

int deepestLeavesSum(TreeNode* root) {
    queue<TreeNode*> que;
    que.push(root);
    int levelValueSum{};
    while(!que.empty()){
        auto size = que.size();
        levelValueSum = 0;
        while(size--){
            auto node = que.front();
            que.pop();
            levelValueSum += node->val;
            if(node->left) que.push(node->left);
            if(node->right) que.push(node->right);
        }
    }
    return levelValueSum;
}

12. 二叉树的最大宽度

662. 二叉树最大宽度

要点:

  • 使用了完全二叉树的节点索引
  • 为了防止索引整数溢出,每层索引都从0开始
int widthOfBinaryTree(TreeNode* root) {
    if(!root)
        return 0;
    queue<pair<TreeNode*,int>> que;
    que.push({root, 1});
    int maxWidth = 1;
    while(!que.empty()){
        auto size = que.size();
        int start = que.front().second;
        int end = 0;
        while(size-- > 0){
            auto nodeInfo = que.front();
            que.pop();
            auto& node = nodeInfo.first;
            auto index = nodeInfo.second;
            end = index;
            if(node->left) que.push({node->left, 2*index-2*start});
            if(node->right) que.push({node->right, 2*index+1-2*start});
        }
        maxWidth = max(maxWidth, end-start+1);
    }
    return maxWidth;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值