算法——队列+宽搜(BFS)

news2024/11/19 14:50:47

队列这种数据结构大都服务于一个算法——宽搜(BFS)。宽搜还可以运用到二叉树、图、迷宫最短路径问题、拓扑排序等等

N叉数的层序遍历

N叉树的层序遍历

题目解析

  • 给定一个 N 叉树,返回其节点值的_层序遍历_。(即从左到右,逐层遍历)。
  • 树的序列化输入是用层序遍历,每组子节点都由 null 值分隔(参见示例)。

算法原理

层序遍历(BFS宽度优先遍历):当我们遍历完 1、3、2、4时,要回过头看拓展3的子节点情况。这一过程属于先进先出的——队列这一数据结构可以解决,以二维数组的形式返回。
image.png

  1. 搞一个队列,如果根节点不为空,先让根节点入队。然后开始while循环,当队列不空的时候,把队头元素1拿出来,让队头元素的子节点2、3、4入队。接着继续将队头元素拿出来,让队头元素2的子节点5、6入队.接着将队头元素3拿出来,7入队,4拿出来,8入队。。继续拿出5、6、7、8(他们都没有子节点,就直接拿出即可)image.png

· image.png

  1. 这里还有一个问题,在一次访问遍历节点时,如果出现不同层的节点元素进入,该怎样统计呢?我们这里只需要设置一个变量,统计元素个数。即当1进入队列时,计数为1;当1出队列时,2、3、4进入。此时个数为3就令变量为3。第二层出完时。第三层四个元素已经全部进入,令变量为4。

代码实现

/*
// 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; // 记录最终结果
        queue<Node*> q; // 层序遍历需要的队列
        if(root == nullptr) return ret;
        q.push(root);
        while(q.size())
        {
            int sz = q.size(); // 先求出本层元素的个数
            vector<int> tmp; // 统计本层的节点
            for(int i = 0; i < sz; i++)
            {
                Node* t = q.front();   //拿出队头元素
                q.pop();
                tmp.push_back(t->val); //将节点加入到最终返回的数组中
                for(Node* child : t->children) // 遍历它的子节点,让下⼀层结点⼊队
                    {
                        if(child != nullptr)
                        q.push(child);
                    }
            }
            ret.push_back(tmp);
        }
        return ret;
    }
};

二叉树的锯齿形层序遍历

二叉树的锯齿形层序遍历

题目解析

image.png

算法原理

解法:层序遍历
在层序遍历的结果存到最终返回结果之前,奇数行直接存入要返回的ret里,偶数行多执行一个逆序返回到ret里面即可。
image.png

代码实现

/**
 * 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*> q;
        q.push(root);
        int level = 1;
        while(q.size())
        {
            int sz = q.size();
            vector<int> tmp;
            for(int i = 0; i < sz; i++)
            {
                auto t = q.front();
                q.pop();
                tmp.push_back(t->val);
                if(t->left) q.push(t->left);
                if(t->right) q.push(t->right);
            }
    
    // 判断是否逆序
            if(level % 2 == 0) reverse(tmp.begin(), tmp.end());
            ret.push_back(tmp);
            level++;
        }
        return ret;
    }
};

二叉树最大宽度

二叉树最大宽度

题目解析

  • 给你一棵二叉树的根节点 root ,返回树的 最大宽度
  • 树的 最大宽度 是所有层中最大的 宽度
  • 每一层的 宽度 被定义为该层最左和最右的非空节点(即,两个端点)之间的长度。将这个二叉树视作与满二叉树结构相同,两端点间会出现一些延伸到这一层的 null 节点,这些 null 节点也计入长度。image.png

算法原理

解法一:硬来层序遍历
统计每⼀层的最⼤宽度,我们优先想到的就是利⽤层序遍历,把当前层的结点全部存在队列⾥⾯,利⽤队列的⻓度来计算每⼀层的宽度,统计出最⼤的宽度。但是,由于空节点也是需要计算在内的。因此,我们可以选择将空节点也存在队列⾥⾯。

当遍历到最后一层时,最后一层宽度为7。可以定义一个empty(统计null个数),从最后一层第一个位置开始扫描,遇到null节点+1,直至遇到下一个有效数字。停止,计算出宽度。然后再将empty置空为0,然后继续向后遍历,因为后面没有真实数字节点,所以最后一个null不计入宽度里。
image.png

但是这里会超时,会有一种极端情况。将3000个节点平均分(题中给的数据范围为3000),如果还按照我们上述计算宽度的算法,那么最后一层将达到21000,这样是大大超出内存的。image.png

解法二:利用数组存储二叉树,给节点编号
树我们不仅有链式存储,还有顺序存储。我们可以通过给二叉树节点编号,通过公式计算给他的子节点编号(两个公式区别就是头结点从1开始计数还是从0开始计数)
image.pngimage.png

  1. 创建一个队列,此时队列里就不仅仅存储节点,我们即存他的节点,也存他的编号。计算宽度方法就是拿出这个队的队头,拿出这个队的对尾,下标相减+1即可;这样就不需要处理空节点了。(有的容器只能访问队头,不能访问队尾,这对于计算宽度就有些麻烦,我们可以用数组模拟队列)image.png

  2. 细节问题:下标有可能溢出。再次回到解法一遇到的极端情况,在那种情况下,最后一层的最后一个节点编号为21500-1.这个数字是任何一个数据类型都存不下的。但是当我们相减之后算出最后结果也是正确的。因为我们的数据存储是一个环形存储,我们最终计算的是距离(绿色部分),这个距离是不会溢出的,所以结果是正确的。我们C++用unsigned int存储就不会报错了image.png

代码实现

/**
 * 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) 
    {
        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;
    }
};

在每个树行中找最大值

在每个树行中找最大值

题目解析

给定一棵二叉树的根节点 root ,请找出该二叉树中每一层的最大值。

算法原理

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

代码实现

/**
 * 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<int> largestValues(TreeNode* root) 
    {
        vector<int> ret;
        if(root == nullptr) return ret;
        queue<TreeNode*> q;
        q.push(root);
        while(q.size())
        {
            int sz = q.size();
            int tmp = INT_MIN;  //初始化为无穷小,让数字与tmp比较
            for(int i = 0; i < sz; i++)
            {
                auto t = q.front(); //拿出队头元素
                q.pop();            //干掉队头元素
                tmp = max(tmp, t->val);  //更新这一层最大值
                if(t->left) q.push(t->left); //让其子节点入队
                if(t->right) q.push(t->right);
            }
            ret.push_back(tmp);
        }
            return ret;
    }
};

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

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

相关文章

c语言结构体学习上篇

文章目录 前言一、结构体的声明1&#xff0c;什么叫结构体?2&#xff0c;结构体的类型3,结构体变量的创建和初始化4&#xff0c;结构体的类型5&#xff0c;结构体的初始化 二、结构体的访问1&#xff0c;结构体成员的点操作符访问2&#xff0c;结构体体成员的指针访问 前言 昨…

安卓在SOA中的运用

安卓在运用SOA研发的过程中&#xff0c;会针对实际情况对研发的架构和流程进行优化&#xff0c;通过优化过的架构和实施方案&#xff0c;不仅可以大大提升了整车开发的效率和灵活行以及功能落地的稳定性&#xff0c;同时也增加了系统的向上兼容性。 目前基于车载SOA系统的研发…

在实际电路中的二极管

常见有静电保护用的TVS&#xff0c;电源DC-DC上用的续流二极管&#xff0c;稳压管&#xff0c;发光LED二极管等 本文概要&#xff1a; 0. 二极管识图1. TVS二极管2. 整流二极管3. 稳压二极管4. 肖特基二极管5. 快回复二极管6. 续流二极管7. 发光二极管8. 变容二极管9. 小结一…

QT----Visual Studio添加QT Multimedia报错未找到

问题描述 引入QSound头文件报错&#xff0c;需要添加multimedia模块。项目–QT project settings–QTmodules&#xff0c;添加上multimedia。但是6.4的qt添加完成后全报错了&#xff0c;且6.4已经把sound删了。 问题解决 其实是安装qt的时候没有把Multimedia这个模块装上 打开…

视频融合云平台/智慧监控平台EassyCVR告警警告出错是什么原因?该如何解决?

视频集中存储/云存储/视频监控管理平台EasyCVR能在复杂的网络环境中&#xff0c;将分散的各类视频资源进行统一汇聚、整合、集中管理&#xff0c;实现视频资源的鉴权管理、按需调阅、全网分发、智能分析等。AI智能/大数据视频分析EasyCVR平台已经广泛应用在工地、工厂、园区、楼…

基于SSM+Jsp的在线商城系统(有文档演示视频,java毕业设计)

大家好&#xff0c;我是DeBug&#xff0c;很高兴你能来阅读&#xff01;作为一名热爱编程的程序员&#xff0c;我希望通过这些教学笔记与大家分享我的编程经验和知识。在这里&#xff0c;我将会结合实际项目经验&#xff0c;分享编程技巧、最佳实践以及解决问题的方法。无论你是…

vue保姆级教程----深入了解Vuex的工作原理

&#x1f4e2; 鸿蒙专栏&#xff1a;想学鸿蒙的&#xff0c;冲 &#x1f4e2; C语言专栏&#xff1a;想学C语言的&#xff0c;冲 &#x1f4e2; VUE专栏&#xff1a;想学VUE的&#xff0c;冲这里 &#x1f4e2; CSS专栏&#xff1a;想学CSS的&#xff0c;冲这里 &#x1f4…

HTML----JavaScript操作对象BOM对象

文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 本章要求 了解BOM模型掌握BOM模型实际应用 一.BOM模型概述 BOM&#xff08;浏览器对象模型&#xff09;是JavaScript中的一个重要概念&#xff0c;它提供了一组用于控制浏览器窗口和页面内容的…

通过IP地址防范钓鱼网站诈骗的有效措施

随着互联网的普及&#xff0c;钓鱼网站诈骗成为一种广泛存在的网络犯罪行为。通过冒充合法网站&#xff0c;攻击者试图窃取用户的敏感信息。本文将探讨如何通过IP地址防范钓鱼网站诈骗&#xff0c;提供一系列有效的措施&#xff0c;以加强网络安全&#xff0c;保护用户免受诈骗…

逻辑回归算法到底能做什么

逻辑回归&#xff08;Logistic Regression&#xff09;是一种广义的线性回归分析模型&#xff0c;常用于数据挖掘、疾病自动诊断、经济预测等领域。它根据给定的自变量数据集来估计事件的发生概率。变量的范围在0和1之间&#xff0c;通常用于二分类问题&#xff0c;最终输出的预…

javafx

JavaFX JavaFX简介 JavaFX是一个用于创建富客户端应用程序的图形用户界面&#xff08;GUI&#xff09;框架。它是Java平台的一部分&#xff0c;从Java 8开始成为Java的标准库。 JavaFX提供了丰富的图形和多媒体功能&#xff0c;使开发人员能够创建具有吸引力和交互性的应用程…

【Proteus仿真】【Arduino单片机】数控稳压可调电源设计

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器&#xff0c;使用动态数码管、按键、PCF8591 AD/DAC、LM358放大电路模块等。 主要功能&#xff1a; 系统运行后&#xff0c;系统默认输出直流5V&#xff0c;数…

C#使用 OpenHardwareMonitor获取CPU或显卡温度、使用率、时钟频率相关方式

C# 去获取电脑相关的基础信息&#xff0c;还是需要借助 外部的库&#xff0c;我这边尝试了自己去实现它 网上有一些信息&#xff0c;但不太完整&#xff0c;都比较零碎&#xff0c;这边尽量将代码完整的去展示出来 OpenHardwareMonitor获取CPU的温度和频率需要管理员权限 在没…

第十二章 需求工程之一图胜千言

需求建模 可视化需求模型能帮助我们识别被遗漏的、不相关的和不一致的需求。数据流图&#xff08;DFD&#xff09;流程图&#xff0c;如泳道图状态转换图&#xff08;STD&#xff09;和状态表对话图决策表和决策树事件-响应表需求树用例图活动图实体关系图&#xff08;ERD&…

Win10升级到Win11

Win10升级到Win11 1. 下载PC健康状况检查应用2. 下载Win111. Windows 11 安装助手2. 创建Windows 11 安装3. 下载Windows 11 磁盘映像&#xff08;ISO&#xff09; 3. Windows 11 安装助手4. 安装成功 有些小伙伴的诉求是想使用一下当前最火的Win11操作系统怎么样。 这里就来安…

Java基础进阶(学习笔记)

注&#xff1a;本篇的代码和PPT图片来源于黑马程序员&#xff0c;本篇仅为学习笔记 static static 是静态的意思&#xff0c;可以修饰成员变量&#xff0c;也可以修饰成员方法 修饰成员的特点&#xff1a; 被其修饰的成员, 被该类的所有对象所共享 多了一种调用方式, 可以通过…

引导过程与服务控制

一、开机启动的完整过程 bios加电自检测-------mbr------grub----------加载内核文件------------启动第一个进程 简述&#xff1a;加电后bios程序会自检硬件&#xff0c;硬件无故障&#xff0c;会根据第一启动项去找内核&#xff0c;一般来说&#xff0c;第一启动项是硬盘&a…

初学者快速入门学习日语,PDF文档音频教学资料合集

一、资料描述 本套学习资料是很全面的&#xff0c;共有734份文件&#xff0c;包括PDF&#xff0c;PPT&#xff0c;表格&#xff0c;图片&#xff0c;音频等多种格式&#xff0c;可以作为初级日语的学习教材&#xff0c;也是非常适合初学者入门的&#xff0c;可以帮助大家快速的…

基本算法——深度优先搜索(DFS)和广度优先搜索(BFS)

深度优先搜索和广度优先搜索&#xff0c;都是图形搜索算法&#xff0c;它两相似&#xff0c;又却不同&#xff0c;在应用上也被用到不同的地方。这里拿一起讨论&#xff0c;方便比较。 一、深度优先搜索 深度优先搜索属于图算法的一种&#xff0c;是一个针对图和树的遍历算法&…

西城微科|充气泵方案PCBA和芯片

智能充气泵是一种常见的充气工具&#xff0c;它在我们的日常生活中扮演着重要的角色。它主要用于给车辆、自行车、橡皮艇、游泳圈等充气&#xff0c;方便人们在各种场合使用。它简单方便的操作&#xff0c;快速高效的充气速度&#xff0c;以及便携的设计&#xff0c;让我们能够…