【基础算法总结】队列 + 宽搜(BFS)

news2024/11/13 9:43:16

队列 + 宽搜BFS

  • 1.N 叉树的层序遍历
  • 2.二叉树的锯齿形层序遍历
  • 3.二叉树最大宽度
  • 4.在每个树行中找最大值

在这里插入图片描述

点赞👍👍收藏🌟🌟关注💖💖
你的支持是对我最大的鼓励,我们一起努力吧!😃😃

1.N 叉树的层序遍历

题目链接: 429. N 叉树的层序遍历

题目分析:

在这里插入图片描述

层序遍历是一层一层的出,需要借助队列使用BFS来完成。比如说遍历到第三层的时候需要从第二层第一个节点的孩子先开始。因此就需要先记录这个节点的信息,遍历完3、4、5回过头再来遍历3的孩子。符合先进先出的思想。所以层序遍历要用到队列来实现。

在这里插入图片描述

算法原理:

解法:BFS(层次遍历/宽度优先搜索/宽度优先搜索)

层序遍历步骤,先搞一个队列,如果根节点不为空,现让根节点入队。接下来就是一个循环,当队列不空的时候,先把队头元素拿出来,然后把队头元素的孩子入队。循环下去直到队列为空为止。就把这棵树层序遍历结束了。

但是这道题要求的是一层一层出,因此我们需要一个变量在每次出队之前先统计一下当前队列中有多少个元素,然后每次出这一层的个数就行了。这个变量就是当前这一层元素的个数。

在这里插入图片描述

/*
// Definition for a Node.
class Node {
public:
    int val;
    vector<Node*> children;

    Node() {}

    Node(int _val) {
        val = _val;
    }

    Node(int _val, vector<Node*> _children) {
        val = _val;
        children = _children;
    }
};
*/

class Solution {
public:
    vector<vector<int>> levelOrder(Node* root) {
        vector<vector<int>> ret; //记录最终结果

        if(root == nullptr) return ret;
 
        queue<Node*> qu;//层序遍历需要的队列
        
        qu.push(root);
        while(!qu.empty())
        {
            int num = qu.size();//先统计出本层元素的个数
            vector<int> tmp; //统计本层的节点
            while(num--)
            {
                Node* front = qu.front();
                tmp.push_back(front->val);
                qu.pop();
                for(auto* cur : front->children)//下一层入队
                {
                    qu.push(cur);
                }
            }
            ret.push_back(tmp);      
        }

        return ret;
        
    }
};

2.二叉树的锯齿形层序遍历

题目链接: 103. 二叉树的锯齿形层序遍历

题目分析:

在这里插入图片描述
锯齿形层序遍历 ,先从左往右,再从右往左进行下一层遍历,以此类推,层与层之间交替进行
在这里插入图片描述

算法原理:

解法:BFS

这道题和上面是一模一样的,只不过有一点小小的改变。发现偶数列是逆序放的。因此可以增加一个标记位,让偶数列的信息逆序即可。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
        vector<vector<int>> ret;
        if(root == nullptr) return ret;

        queue<TreeNode*> qu;
        qu.push(root);
        int level = 1;
        while(!qu.empty())
        {
            int k = qu.size();
            vector<int> tmp;
            while(k--)
            {
                TreeNode* t = qu.front();
                qu.pop();
                tmp.push_back(t->val);

                if(t->left) qu.push(t->left);
                if(t->right) qu.push(t->right);
            }

            if(level % 2 == 0) reverse(tmp.begin(),tmp.end());
            ret.push_back(tmp);
            ++level;
        }
        return ret;
    }
};

3.二叉树最大宽度

题目链接:662. 二叉树最大宽度

题目分析:

在这里插入图片描述

每一层的 宽度 被定义为该层最左和最右的非空节点(即,两个端点)之间的长度。将这个二叉树视作与满二叉树结构相同,两端点间会出现一些延伸到这一层的 null 节点,这些 null 节点也计入长度。

最左和最右非空节点中间的nullptr也要加入计算到长度。
在这里插入图片描述

算法原理:

解法一:硬来

依旧是创建一个队列,这次入队不一样即使是一个节点的左孩子或者右孩子是null也要入队。然后在每一层出队之前都可以统计这一层有多宽。比如这棵树第三层没有问题宽度就是这一层的节点数,但是第四层就有问题了,实际宽度并不是这一层节点数。那如何统计这一层的实际宽度呢?方法很简单,我们在遍历这一层的时候可以再来一个empty指针,当这个指针遇到不是 null 的时候 宽度+1,如果是空的话就统计就循环把null拿到,如果碰到非空的时候就把 null 的个数 加入到 宽度,然后把null 的个数记为0。如果直到遍历到队列结尾还没有碰到非空 就不要把 null 结点数加入到 宽度。

在这里插入图片描述

但是这个方法会超时!
在这里插入图片描述

虽然节点有1-3000个,但是如果是系啊没这种左右非常平均有1500个节点。最后一层一共2^1499个节点,那太恐怖了。内存根本放不下。

在这里插入图片描述

接下来我们换一种策略。

树不仅可以用链式存储,也可以用数组存储起来,例如堆。

解法二:利用数组存储二叉树的方式,给结点编号

对一个结点i,如何找它的左右孩子,有两种方法如下:

在这里插入图片描述
有这个启发之后,那为何不给树每个结点都加上一个编号,孩子是null结点就不用在放入队列了,队列中只存储有孩子的结点和编号,然后这一层把第一个结点的编号和最后一个结点的编号拿出来,然后 最后一个结点的编号 减去 第一个结点的编号 + 1 不就是这一层宽度吗!

queue<pair<TreeNode*,int>>

还是这一层出队之前把第一个结点和最后一个结点拿到,取出里面的编号,做对应的计算。 如 7 - 4 + 1 = 4,14 - 8 + 1 = 7。比较每层宽度取最大的宽度。
在这里插入图片描述

上面是用队列来做的,甚至可以不用队列,就用两个数组就可以模拟队列。因此
vector<pair<TreeNode*,int>> 也是可以的。

这里还有一个细节问题:下标有可能会溢出。还是刚才的例子,左边来1500个节点,右边来1500个节点。最后一个节点编号是2^1500 - 1,不管用什么类型都存不下!别说这里int,甚至double都不行。

在这里插入图片描述

难道要用字符串来存,然后做高精度加减吗,其实也不用, 因为我们最后是做减法的,即使溢出,但是相减的结果也是正确的。

我们的数据存储其实是可以看作一个环,如char -128 ~ 127
虽然正数会溢出到负数, 但是 我们做减法求的是两个数之间的距离,当两个数相减就会把结果修正,因为求的是之间的距离,这段距离是正的并且不会溢出。

但是前提不能是超过一圈然后到的这个位置。此时减肯定是一个错误。但是这道题告诉题目数据保证答案将会在 32 位 带符号整数范围内。因此pair 内 int 换成 unsigned int

vector<pair<TreeNode*,unsigned int>>

在这里插入图片描述

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    int widthOfBinaryTree(TreeNode* root) {
        queue<pair<TreeNode*,unsigned int>> qu;
        unsigned int ret = 0;
        if(root == nullptr) return ret;
        
        qu.push(make_pair(root,1));
        while(!qu.empty())
        {   
            //先更新这一层的宽度

            //pari对象里面的成员会分别存到 first -> x1, second -> y1
            auto& [x1,y1] = qu.front();
            auto& [x2,y2] = qu.back();
            ret = max(ret, y2 - y1 + 1);

            //让下一层入队
            int k = qu.size();
            while(k--)
            {
                auto [x,y] = qu.front();
                qu.pop();

                if(x->left) qu.push(make_pair(x->left,2 * y));
                if(x->right) qu.push(make_pair(x->right,2 * y +1));
            }
        }

        return ret;
    }
};

数组模拟队列

class Solution {
public:
    int widthOfBinaryTree(TreeNode* root) {
        vector<pair<TreeNode*, unsigned int>> q; // ⽤数组模拟队列
        q.push_back({root, 1});
        unsigned int ret = 0;
        while(q.size())
        {
            // 先更新这⼀层的宽度
            auto& [x1, y1] = q[0];
            auto& [x2, y2] = q.back();
            ret = max(ret, y2 - y1 + 1);

            // 让下⼀层进队
            //数组队头不好出,那就不出,再来一个数组记录孩子节点,最后拷贝回去
            vector<pair<TreeNode*, unsigned int>> tmp; // 让下⼀层进⼊这个队列
            for(auto& [x, y] : q)
            {
                if(x->left) tmp.push_back({x->left, y * 2});
                if(x->right) tmp.push_back({x->right, y * 2 + 1});
            }
            q = tmp;
        }
        return ret;
    }
};

4.在每个树行中找最大值

题目链接:515. 在每个树行中找最大值

题目描述:

在这里插入图片描述

算法原理:

解法:利用层序遍历,统计出每一层的最大值

class Solution {
public:
    vector<int> largestValues(TreeNode* root) {
        vector<int> ret;
        if(root == nullptr) return ret;
        queue<TreeNode*> qu;
        qu.push(root);

        while(qu.size())
        {
            int k = qu.size();
            int tmp = INT_MIN;
            while(k--)
            {
                TreeNode* t = qu.front();
                qu.pop();
                tmp = max(tmp, t->val);

                if(t->left) qu.push(t->left);
                if(t->right) qu.push(t->right);
            }
            ret.push_back(tmp);
        }
        return ret;

    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1953539.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

活动报名小程序

#活动报名工具# # 活动报名小程序 ## 项目简介 一款通用的活动报名工具&#xff0c;包含活动展示&#xff0c;微信支付&#xff0c;订单管理&#xff0c;分享评价等功能。 品客聚精彩&#xff0c;有你才精彩&#xff01;不只有线下活动还可以进行线上裂变活动。 …

SpringBoot知识笔记

一、基本概念 1.1 特性 起步依赖 自动配置 其它特性:内嵌的Tomcat、Jetty(无需部署WAR文件),外部配置,不需要XML配置(properties/yml)。 1.2 配置文件 SpringBoot提供了多种属性配置方式 //application.properties server.port=9090 server.servlet.context-path…

自从与泰勒斯威夫特约会以来,特拉维斯凯尔西表现得像布拉德皮特一样挥霍打扮

今年对于泰勒斯威夫特和特拉维斯凯尔西来说可谓是风云变幻的一年&#xff0c;他们秘密开始约会&#xff0c;然后有了今年最引人瞩目的恋情。对于这位 NFL 运动员来说&#xff0c;这是一个巨大的变化&#xff0c;因为随着斯威夫特的粉丝们了解了凯尔西家族的一切&#xff0c;他的…

人机交互不仅仅是科技问题

人机交互不仅仅局限于物理和数理科学的应用&#xff0c;还涉及到更广泛的管理、文理、哲学、艺术、伦理以及法律等领域。下面这些领域在人机协同和智能系统应用中扮演着重要角色&#xff1a; 智能系统在企业管理、资源分配、决策支持等方面的应用&#xff0c;可以帮助管理者优化…

自学网络安全,从小白到大神的破茧之路!

在当今数字化高速发展的时代&#xff0c;网络安全已经成为了至关重要的领域。无论是个人的隐私保护&#xff0c;还是企业、国家的关键信息资产维护&#xff0c;都离不开网络安全的有力保障。出于对这一领域的浓厚兴趣以及对未来职业发展的清晰规划&#xff0c;我毅然决然地踏上…

基于物联网的区块链算力网络,IGP/BGP协议

目录 基于物联网的区块链算力网络 IGP/BGP协议 IGP(内部网关协议) BGP(边界网关协议) 内部使用ISP的外部使用BGP的原因 一、网络规模和复杂性 二、路由协议的特性 三、满足业务需求 四、结论 基于物联网的区块链算力网络 通 过 多个物联网传感器将本地计算…

科普文:kubernets原理

kubernetes 已经成为容器编排领域的王者&#xff0c;它是基于容器的集群编排引擎&#xff0c;具备扩展集群、滚动升级回滚、弹性伸缩、自动治愈、服务发现等多种特性能力。 本文将带着大家快速了解 kubernetes &#xff0c;了解我们谈论 kubernetes 都是在谈论什么。 一、背…

Godot入门 08敌人

添加Node2D节点&#xff0c;添加AnimatedSprite2D节点。 从精灵表中添加帧 设置加载后自动播放&#xff0c;10FPS&#xff0c;并拖动动画到水平线上 插入死亡区域场景 添加CollisionShape2D节点&#xff0c;设置矩形碰撞形状。按住ALT可对称修改碰撞形状。 重命名Node2D为Slim…

数据结构之探索“堆”的奥秘

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a;数据结构&#xff08;Java版&#xff09; 目录 堆的概念 堆的创建 时间复杂度分析&#xff1a; 堆的插入与删除 优先级队列 PriorityQ…

nodejs - express 学习笔记

express 是一个基于 Node.js 平台的极简、灵活的 WEB 应用开发框架&#xff0c;官方网址&#xff1a;https://www.expressjs. com.cn/ 简单来说&#xff0c;express 是一个封装好的工具包&#xff0c;封装了很多功能&#xff0c;便于我们开发 WEB 应用&#xff08;HTTP 服务&am…

TinyALSA 简介

TinyALSA 是一个轻量级的 ALSA&#xff08;Advanced Linux Sound Architecture&#xff0c;高级 Linux 音频架构&#xff09;实现&#xff0c;用于与 Linux 内核中的 ALSA&#xff08;高级 Linux 声音架构&#xff09;进行交互&#xff0c;旨在为嵌入式系统和资源受限的设备提供…

提取视频中的文字如何提取?分享4种简单提取方法

在短视频时代&#xff0c;视频已成为信息传播的重要载体。然而&#xff0c;面对海量的视频资源&#xff0c;如何高效提取其中的文字信息&#xff0c;成为许多人关注的焦点&#xff0c;因为快速提取出视频中的文字可以帮助我们整理、编辑文本信息&#xff0c;下面给大家分享4种简…

Linux 基础开发工具 : Vim编辑器

Vim 是 Linux 和其他类 Unix 系统上广泛使用的文本编辑器之一。它基于更早的 vi 编辑器&#xff0c;但添加了许多增强功能和扩展。Vim 是“Vi IMproved”的缩写&#xff0c;意为“改进的 Vi”&#xff0c;我们常使用Vim编辑器编写c/c代码。 ps&#xff1a;该篇介绍均为最基础介…

【LeetCode:3106. 满足距离约束且字典序最小的字符串 + 贪心】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

谷粒商城实战-58-商品服务-API-三级分类-删除-批量删除小结

文章目录 一&#xff0c;增加一个批量删除的按钮并绑定事件二&#xff0c;全栈工程师三&#xff0c;逆向工程在全栈开发中的应用提升效率的方式&#xff1a;使用案例&#xff1a; 这一节的主要内容是开发批量删除分类的功能。 一&#xff0c;增加一个批量删除的按钮并绑定事件 …

数论第一节:整数的可除性

[TOC ] 1、整除的概念 整除&#xff1a; 设a&#xff0c;b∈Z&#xff0c;若存在整数c∈Z&#xff0c;s.t. a bc&#xff0c;则称b整除a&#xff0c;记为 b ∣ a b|a b∣a否则称b不整除a。 带余除法&#xff1a; 设 a &#xff0c; b ∈ z a&#xff0c;b∈z a&#xff0c;b∈…

Jupyter notebook无法自动关联打开浏览器,怎么办?

最近为了方便进行数据分析和处理&#xff0c;在电脑上安装了Anaconda。 Anaconda 是一个功能强大的数据科学平台&#xff0c;它包含了‌conda、Python以及180多个科学包及其依赖项。 Anaconda 常常用于科学计算、数据分析和人工智能等领域&#xff0c;并且得到了广大开发者的…

【中项】系统集成项目管理工程师-第5章 软件工程-5.5部署交付

前言&#xff1a;系统集成项目管理工程师专业&#xff0c;现分享一些教材知识点。觉得文章还不错的喜欢点赞收藏的同时帮忙点点关注。 软考同样是国家人社部和工信部组织的国家级考试&#xff0c;全称为“全国计算机与软件专业技术资格&#xff08;水平&#xff09;考试”&…

界面控件Telerik UI for WPF 2024 Q2亮点 - 全新的AIPrompt组件

Telerik UI for WPF拥有超过100个控件来创建美观、高性能的桌面应用程序&#xff0c;同时还能快速构建企业级办公WPF应用程序。UI for WPF支持MVVM、触摸等&#xff0c;创建的应用程序可靠且结构良好&#xff0c;非常容易维护&#xff0c;其直观的API将无缝地集成Visual Studio…

PostgreSQL成为最受欢迎的数据库; TiDB马拉松大赛开启, Serverless和Vector为比赛焦点

重要更新 1. TiDB Hackathon大赛报名开启&#xff0c;总奖金达21万&#xff0c;主题是基于 TiDB Serverless 内置的向量搜索功能&#xff08;Vector Search&#xff09;构建 AI 创新应用&#xff0c;感兴趣的可以报名参加。( [1] ) 2. Stack Overflow 2024 开发者调研结果公布…