算法沉淀——拓扑排序

前言:

首先我们需要知道什么是拓扑排序?

在正式讲解拓扑排序这个算法之前,我们需要了解一些前置知识(和离散数学相关)

1、有向无环图:

指的是一个无回路的有向图。

入度:有向图中某点作为图中边的终点的次数之和

出度:有向图中某点作为图中边的起点的次数之和

2、AOV网:顶点活动图

在有向无环图中,用顶点来表示一个活动,用边来表示活动的先后顺序的图结构。

举个例子:

在下面的这张图中,1这个点的入度就是0,2这个点的入度就是2,因为有两条有向线段指向2这个点。

3、拓扑排序:

简而言之就是找到事情的先后顺,拓扑排序的结果可能不是唯一的。

如何排序?

  1. 找出图中入度为0的点,然后输出
  2. 删除与该点连接的边
  3. 重复1、2操作,直到图中没有点或者没有入度为0点为止。(有可能有环

重要应用:判断有向图中是否有环

4、如何用代码实现拓扑排序呢?(重点)

首先,我们需要根据题意去建图!!!(利用哈希表等容器,会结合题目详细解析)。

接着,建好图后,借助队列,来一次BFS即可。

1、初始化:把所有入度为0的点加入到队列中

2、当队列不为空时:

  1. 拿出队头元素,加入到最终结果中;
  2. 删除与该元素相连的边
  3. 判断:与删除边相连的点,是否入度变成0,如果入度为0,加入到队列中

经典例题1:207. 课程表 - 力扣(LeetCode)

题目描述:

题目解析:

我们可以根据题意,将课程之间的联系抽象成图

而题目所说的判断能否完成所有的课程学习,问的就是这个图有无环!!!

知道本题利用拓扑排序解决,那第一步就是如何建图呢

灵活使用语言提供的容器

邻接表:

我们可以利用哈希表来实现图中点与点之间的关系。

同时我们也需要另一个容器存储每个点的入度。

原码:

class Solution {
public:
    bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {
        unordered_map<int,vector<int>> hash; //邻接表存图
        vector<int> in(numCourses); //标记每个点的入度
        //开始建图
        for(auto& e : prerequisites)
        {
            int a = e[0];
            int b = e[1];
            hash[b].push_back(a);
            in[a]++;
        }
        queue<int> q;
        //将度为0的边存到队列中
        for(int i = 0; i < numCourses; i++)//
        {
            cout << i << endl;
            if(in[i] == 0) q.push(i);
        }
        //进行拓扑排序bfs
        while(q.size())
        {
            int t = q.front();
            q.pop();
            //将这个点删除,并且删除跟他相连的边
            for(int i : hash[t])
            {
                in[i]--;
                if(in[i] == 0) q.push(i);
            }
        }
        //判断是否有环
        for(auto i : in)
        {
            if(i > 0) return false;
        }
        return true;
 
    }
};

例题二:LCR 114. 火星词典 - 力扣(LeetCode)

题目描述:

题目解析:

本题也是拓扑排序的经典例题。

1、如何搜集信息?

两层for循环

2、拓扑排序:

1、建图

hash<char, hash<char>> edges;

注意第一个hash表示map类型,第二个hash表示set。

这就需要我们对容器的灵活使用!

2、统计入度信息

hash<char, int> in; 注意必须要初始化

3、如何收集信息:双指针

4、细节问题:

abc和ab,若abc在前明显不符合要求,需要提前返回空字符串。

原码:

class Solution {
public:
    string alienOrder(vector<string>& words) {
        unordered_map<char, unordered_set<char>> edges; // 邻接表来存储图
        unordered_map<char, int> in; // 统计入度
        string ans;

        int n = words.size();
        //必须要对入度进行初始化,不然入度为0的点根本没有存进去
        for(auto& i : words)
        {
            for(auto k : i)
            in[k] = 0;
        }

        for(int i = 0; i < n; i++)
        {
            for(int j = i + 1; j < n; j++)
            {
                string a = words[i];
                string b = words[j];
                int len1 = a.size(), len2 = b.size();
                int len = min(len1, len2);
                int flag = 0;
                for(int k = 0; k < len; k++)
                {
                    //正常情况
                    if(a[k] != b[k])
                    {
                        if(!edges.count(a[k]) || !edges[a[k]].count(b[k]))
                        {
                            edges[a[k]].insert(b[k]);
                            in[b[k]]++;
                        }
                        flag = 1;

                        break;
                    }
                }
                //判断特殊情况
                if(len1 > len2 && !flag)
                {
                    return ans;
                }
            }
        }

        //开始拓扑排序
        queue<char> q;
        //注意map的范围for表示!!!
        for(auto& [a, b]: in)
        {
            if(b == 0)
            {
                q.push(a);
            }
        }
        
        while(q.size())
        {
            char tmp = q.front();
            q.pop();
            ans += tmp;
            cout << ans << endl;
            for(char i : edges[tmp])
            {
                in[i]--;
                if(in[i] == 0) q.push(i);
            }
        }
        //判断是否有环
        for(auto& [a,b] : in)
        {
            if(b != 0) return "";
        }
        return ans;
    } 
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

数字图像处理——直方图的均衡化

1.方法简介&#xff1a; 直方图均衡化通常用来增加许多图像的全局对比度&#xff0c;尤其是当图像的有用数据的对比度相当接近的时候。通过这种方法&#xff0c;亮度可以更好地在直方图上分布。这样就可以用于增强局部的对比度而不影响整体的对比度&#xff0c;直方图均衡化通…

01---java面试八股文——mybatis-------10题

1、什么是MyBatis Mybatis是一个半ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;它内部封装了JDBC&#xff0c;开发时只需要关注SQL语句本身&#xff0c;不需要花费精力去处理加载驱动、创建连接、创建statement等繁杂的过程。程序员直接编写原生态sql&#xff0c…

基于51单片机和MAX1898的智能手机充电器设计

**单片机设计介绍&#xff0c;基于51单片机和MAX1898的智能手机充电器设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于51单片机和MAX1898的智能手机充电器设计概要 一、引言 随着智能手机的普及&#xff0c;其电池续航…

图像分类实战:深度学习在CIFAR-10数据集上的应用

1.前言 图像分类是计算机视觉领域的一个核心任务&#xff0c;算法能够自动识别图像中的物体或场景&#xff0c;并将其归类到预定义的类别中。近年来&#xff0c;深度学习技术的发展极大地推动了图像分类领域的进步。CIFAR-10数据集作为计算机视觉领域的一个经典小型数据集&…

NumPy介绍及其应用领域

1.NumPy介绍 ​NumPy&#xff08;Numerical Python&#xff09;是 Python 的一个开源的扩展程序库&#xff0c;支持大量的维度数组与矩阵运算&#xff0c;此外也针对数组运算提供大量的数学函数库。NumPy的前身为Numeric&#xff0c;起初由Jim Hugunin与其他协作者共同开发&…

机器学习和深度学习的简单对比

如图1-2所示&#xff0c;深度学习&#xff08;DeepLearning&#xff0c;DL&#xff09;属于机器学习的子类。它的灵感来源于人类大脑的工作方式&#xff0c;这是利用深度神经网络来解决特征表达的一种学习过程。深度神经网络本身并非是一个全新的概念&#xff0c;可理解为包含多…

Python基础入门 --- 9.异常、模块

文章目录 第九章&#xff1a;9.异常9.1 异常的捕获9.1.1 捕获指定异常9.1.2 捕获多个异常9.1.3 捕获全部异常9.1.4 异常else9.1.5 异常的finally 9.2 异常的传递性9.3 Python模块9.3.1 模块的导入import模块名from 模块名 import 功能名from 模块名 import *as定义别名 9.3.2 自…

2024年水电站大坝安全监测工作提升要点

根据《水电站大坝运行安全监督管理规定》&#xff08;国家发改委令第23号&#xff09;和《水电站大坝运行安全信息报送办法》&#xff08;国能安全〔2016〕261号&#xff09;的相关规定、要求&#xff0c;电力企业应当在汛期向我中心报送每日大坝汛情。近期&#xff0c;全国各地…

帆软报表踩坑日记

最近公司项目要是使用报表&#xff0c;公司使用的是帆软这个国产软件&#xff0c;自己也是学习使用&#xff0c;在使用的过程中记一下问题以及解决方式 公司使用的是帆软8这个版本&#xff0c;比较老了。 首先是表格中的扩展&#xff0c;就是当我们根据数据库查询数据然后放到表…

谷粒商城实战(007 压力测试)

Java项目《谷粒商城》架构师级Java项目实战&#xff0c;对标阿里P6-P7&#xff0c;全网最强 总时长 104:45:00 共408P 此文章包含第141p-第p150的内容 简介 安装jmeter 安装jmeter 使用中文 这样写就是200个线程循环100次 一共是2万个请求 介绍线程组 添加请求 可以是htt…

供应链销售数据分析丨跟张良均老师学大数据人工智能(第二期)

师傅带练 项目背景 通过大数据分析怡亚通供应链商品的销售数据&#xff0c;分析不同店铺地址、不同销售季节和不同产品的销售数据&#xff0c;可以给于客户铺货支持以及经营策略建议&#xff0c;帮助怡亚通更好地优化库存管理、供货策略和市场营销活动&#xff0c;从而提升销…

计算机视觉的应用25-关于Deeplab系列语义分割模型的应用场景,以及空洞卷积的介绍

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下计算机视觉的应用25-关于Deeplab系列语义分割模型的应用场景&#xff0c;以及空洞卷积的介绍。Deeplab是Google研发的一系列深度学习模型&#xff0c;主要用于图像语义分割任务&#xff0c;其在众多应用场景中展现出…

56、FreeRTOS/GPIO与定时器相关学习20240329

一、代码实现控制开发板上的指示灯闪烁。 /* USER CODE BEGIN 0 */ //利用定时器机制 定时器溢出时对应的回调函数实现如下 //本次实现控制PB0&#xff0c;PB1两个灯 int flag1 0,flag2 0;//使用一个标记执行以下代码 会造成一个灯常亮 另一个常灭 void HAL_TIM_PeriodElaps…

JavaSE day15 笔记

第十五天课堂笔记 数组 可变长参数★★★ 方法 : 返回值类型 方法名(参数类型 参数名 , 参数类型 … 可变长参数名){}方法体 : 变长参数 相当于一个数组一个数组最多只能有一个可变长参数, 并放到列表的最后parameter : 方法参数 数组相关算法★★ 冒泡排序 由小到大: 从前…

【threejs】较大物体或shape的贴图较小问题处理方法

问题 有的场景内相对体型差距过大的物体&#xff08;如山地 海洋等&#xff09;由于尺寸问题&#xff0c;加载贴图过于小&#xff0c;同时shader也无法完全展示&#xff0c;如图 我们可以获取物体的uv&#xff0c;进行缩放使得贴图可以完全展开 如果uv是乱的 可以用xyz坐标最…

模组软件通用|GNSS坐标系的转换

“GNSS定位不准确&#xff0c;漂移了好几公里&#xff0c;是怎么回事呢&#xff1f;”很多用户在初次使用GNSS定位时都会有这样的问题&#xff0c;这主要是由于GNSS坐标系转换错误造成的位置偏移问题。下面将从常见坐标系、国内地图软件采用的坐标系、经纬度表示方法、示例以及…

Qt 完成图片的缩放拖动

1. 事件和函数 主要使用事件paintEvent(QPaintEvent *event)和drawTiledPixmap函数实现绘图。 paintEvent事件在改变窗口大小、移动窗口、手动调用update等情形下会被调用。需先了解下绘图该函数的用法。 - QPainter::drawTiledPixmap(int x, int y, int w, int h, const QPi…

深入并广泛了解Redis常见的缓存使用问题

Redis 作为一门主流技术&#xff0c;缓存应用场景非常多&#xff0c;很多大中小厂的项目中都会使用redis作为缓存层使用。 但是Redis作为缓存&#xff0c;也会面临各种使用问题&#xff0c;比如数据一致性&#xff0c;缓存穿透&#xff0c;缓存击穿&#xff0c;缓存雪崩&#…

k8s下搭建redis集群

记录一下近期实现的在k8s上搭建redis集群的过程 1、新建存储类 主要是为了和其它服务的存储类区分一下 redis-beta-storage 2、编写configMap redis启动时从configMap中读取配置 bind&#xff1a;默认的127.0.0.1可能会导致其它ip地址无法远程访问&#xff0c;因此修改为0.0…

stm32定时器中断函数回调函数

方式一&#xff1a;stm32定时器中断可以直接在硬件中断函数TIM3_IRQHandler执行。 在HAL库中可以注册回调函数&#xff0c;在定时器中断发生时调用注册的函数&#xff0c;这样可以统一接口&#xff0c;大大提高函数可读性&#xff0c;和硬件解耦提高程序可移植性。 使用过程如…