【拓扑系列】拓扑排序

【拓扑系列】拓扑排序

  • 前言
    • 认识有向无环图
    • 认识AOV网:顶点活动图
    • 拓扑排序
  • 1. 课程表
    • 1.1 题目来源
    • 1.2 题目描述
    • 1.3 题目解析
  • 2. 课程表 II
    • 2.1 题目来源
    • 2.2 题目描述
    • 2.3 题目解析
  • 3. LCR 114. 火星词典
    • 3.1 题目来源
    • 3.2 题目描述
    • 3.3 题目解析

前言

认识有向无环图

图中不会形成环状的有向图就是有向无环图。

在这里插入图片描述

入度和出度

  • 出度:一个顶点指向另一个节点的数量。
  • 入度:一个顶点有多少是指向它的。

在这里插入图片描述

认识AOV网:顶点活动图

  • AOV网(Activity On Vertex Network)‌是一个用顶点表示活动,有向边表示活动之间优先关系的有向图。在这个图中,顶点代表工程中的各个活动,而有向边则反映了这些活动之间的先后依赖关系。

AOV网的特点包括:

  1. 顶点表示活动‌:在AOV网中,每一个顶点都代表一个具体的活动,这些活动构成了工程的各个组成部分。
    ‌有向边表示优先关系‌:有向边用来表示活动之间的优先关系,即一个活动必须在另一个活动完成之后才能开始。这种关系通过有向边在图中进行表示,从而形成一个有向图。
  2. 无回路‌:AOV网中不允许存在回路,即不存在一个活动直接或间接地依赖于它自身的完成,这保证了活动的逻辑顺序和工程的可行性。
  3. AOV网的概念在现代化管理中非常有用,特别是在描述和分析一项工程的计划和实施过程中。通过将工程分解为多个小的子工程(即活动),并用有向图来表示这些活动之间的依赖关系,可以帮助理解和优化工程的执行流程。此外,拓扑排序是AOV网的一个重要应用,用于判断网中是否存在环,确保所有活动都能按照正确的顺序执行,避免出现无法完成的循环依赖‌。

拓扑排序

  • 拓扑排序‌是对一个有向无环图(DAG)进行排序,将图中的所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。这样的线性序列称为满足拓扑次序的序列,简称拓扑序列。‌12

  • 拓扑排序常用于确定一个依赖关系集中事物发生的顺序。例如,在项目管理中,可以确定项目各阶段之间的依赖关系,从而计算出项目的执行顺序。

  • 拓扑排序的实现方法通常使用深度优先搜索(DFS)或广度优先搜索(BFS)。在树结构中,拓扑排序可以简单地通过层次遍历实现。

我们用更直接的话来讲就是:拓扑排序的作用就是找到做事情的先后顺序,并且拓扑排序的结果不唯一。

拓扑排序的具体操作:

  1. 找出图中入度为0的节点,然后输出
  2. 删除这个节点的连接的边
  3. 重复步骤1,2操作,直到图中没有点或者没有入度为0的节点为止(可能存在环)。所以可以根据这个特性判断图中是否有环。

实现拓扑排序:借助队列,来一次bfs即可
4. 初始化:将所有入度为0的节点添加的队列中
5. 当队列不为空的时候,拿出队头元素添加到结果中,删除该元素相连的边,判断删完后与删除边相连接的点入度是否为0,如果为0添加到队列,然后一直循环。

1. 课程表

1.1 题目来源

207. 课程表

1.2 题目描述

你这个学期必须选修 numCourses 门课程,记为 0 到 numCourses - 1 。

在选修某些课程之前需要一些先修课程。 先修课程按数组 prerequisites 给出,其中 prerequisites[i] = [ai, bi] ,表示如果要学习课程 ai 则 必须 先学习课程 bi 。

例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1 。
请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false

  1. 示例 1:
    输入:numCourses = 2, prerequisites = [[1,0]]
    输出:true
    解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。
  2. 示例 2:
    输入:numCourses = 2, prerequisites = [[1,0],[0,1]]
    输出:false
    解释:总共有 2 门课程。学习课程 1 之前,你需要先完成​课程 0 ;并且学习课程 0 之前,你还应先完成课程 1 。这是不可能的。

提示:
1 <= numCourses <= 2000
0 <= prerequisites.length <= 5000
prerequisites[i].length == 2
0 <= ai, bi < numCourses
prerequisites[i] 中的所有课程对 互不相同

1.3 题目解析

class Solution {
public:vector<vector<int>> edges;vector<int> in;queue<int> q;vector<int> ret;bool bfs(int n){// 将入度数为0的放入队列for (int i = 0; i < n; i++){if (in[i] == 0){q.push(i);}}while (!q.empty()){int t = q.front();q.pop();ret.push_back(t);for (auto v : edges[t]){if(--in[v] == 0){q.push(v);}}}return ret.size() == n; // 判断是否有环}bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {in.resize(numCourses);edges.resize(numCourses);// 建图for (auto point : prerequisites){edges[point[1]].push_back(point[0]);//计入计入入度数in[point[0]]++;}return bfs(numCourses);}
};

2. 课程表 II

2.1 题目来源

210. 课程表 II

2.2 题目描述

现在你总共有 numCourses 门课需要选,记为 0 到 numCourses - 1。给你一个数组 prerequisites ,其中 prerequisites[i] = [ai, bi] ,表示在选修课程 ai 前 必须 先选修 bi 。

例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示:[0,1] 。
返回你为了学完所有课程所安排的学习顺序。可能会有多个正确的顺序,你只要返回 任意一种 就可以了。如果不可能完成所有课程,返回 一个空数组 。

  1. 示例 1:
    输入:numCourses = 2, prerequisites = [[1,0]]
    输出:[0,1]
    解释:总共有 2 门课程。要学习课程 1,你需要先完成课程 0。因此,正确的课程顺序为 [0,1] 。
  2. 示例 2:
    输入:numCourses = 4, prerequisites = [[1,0],[2,0],[3,1],[3,2]]
    输出:[0,2,1,3]
    解释:总共有 4 门课程。要学习课程 3,你应该先完成课程 1 和课程 2。并且课程 1 和课程 2 都应该排在课程 0 之后。
    因此,一个正确的课程顺序是 [0,1,2,3] 。另一个正确的排序是 [0,2,1,3]
  3. 示例 3:
    输入:numCourses = 1, prerequisites = []
    输出:[0]

提示:
1 <= numCourses <= 2000
0 <= prerequisites.length <= numCourses * (numCourses - 1)
prerequisites[i].length == 2
0 <= ai, bi < numCourses
ai != bi
所有[ai, bi] 互不相同

2.3 题目解析

class Solution {
public:vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {vector<vector<int>> edges(numCourses);vector<int> in(numCourses);vector<int> ret;queue<int> q;// 建图for (auto v : prerequisites){edges[v[1]].push_back(v[0]);in[v[0]]++;}//将入度数为0的放入队列for (int i = 0; i < numCourses; i++){if (in[i] == 0) q.push(i);}//深度遍历while (!q.empty()){int t = q.front();q.pop();ret.push_back(t);for (auto v : edges[t]){if (--in[v] == 0)q.push(v);}}if (ret.size() == numCourses)return ret;else return vector<int>();}
};

3. LCR 114. 火星词典

3.1 题目来源

LCR 114. 火星词典

3.2 题目描述

现有一种使用英语字母的外星文语言,这门语言的字母顺序与英语顺序不同。

给定一个字符串列表 words ,作为这门语言的词典,words 中的字符串已经 按这门新语言的字母顺序进行了排序 。

请你根据该词典还原出此语言中已知的字母顺序,并 按字母递增顺序 排列。若不存在合法字母顺序,返回 “” 。若存在多种可能的合法字母顺序,返回其中 任意一种 顺序即可。

字符串 s 字典顺序小于 字符串 t 有两种情况:

在第一个不同字母处,如果 s 中的字母在这门外星语言的字母顺序中位于 t 中字母之前,那么 s 的字典顺序小于 t 。
如果前面 min(s.length, t.length) 字母都相同,那么 s.length < t.length 时,s 的字典顺序也小于 t 。

  1. 示例 1:
    输入:words = [“wrt”,“wrf”,“er”,“ett”,“rftt”]
    输出:“wertf”
  2. 示例 2:
    输入:words = [“z”,“x”]
    输出:“zx”
  3. 示例 3:
    输入:words = [“z”,“x”,“z”]
    输出:“”
    解释:不存在合法字母顺序,因此返回 “” 。
  4. 示例 4:
    输入:words = [“abc”,“ab”]
    输出:“”
    解释:不存在合法字母顺序,因此返回 “” 。

提示:
1 <= words.length <= 100
1 <= words[i].length <= 100
words[i] 仅由小写英文字母组成

3.3 题目解析

这个题目的关键就在于要理解题目意思,题目意思是,两个字符进行对比,一旦遇到了不相同的字符,字符在前面的是小于字符在后面的,并且如果s1的长度小于s2的话并且s1的长度大于s2的长,如果s2等于s1的部分字符串,就类似于示例4,那么也是不符合的。
在这里插入图片描述
所以我们该怎么处理words字典呢,这里我们就可以直接使用两层for循环,依次进行比较,并且一旦找到了的话其实可以用图的方式进行来连接例如(a->b 就标识a小于b)于是有了这个思路我们就可以使用拓扑排序了。

上面的几题都是对int整形进行比较的,也是使用的vector来存放图,但是这里就不一样了,类型是char,所以这里我们一应该使用hash表来进行存储,即unordered_map<char, unordered_set< char >>,因为字典中会后重复的,所以我们的邻接表也应该使用一个hash来进行存储。
而至于我们存放入度数的话也不能直接使用vector或者数组来存储了,也应该使用hash来进行存储。

所以我们的具体步骤就是:

  1. 创建unordered_map<char, unordered_set< char>> edges来建图,创建unordered_map<char, int> in来存放入度数
  2. 遍历整个字典将初始化入度in
  3. 使用双指针遍历字典,建立图
  4. 深度遍历
class Solution {
public:unordered_map<char, unordered_set<char>> edges;unordered_map<char, int> in;queue<char> q;string ret;string alienOrder(vector<string>& words) {for (auto &s : words){for (auto c : s){in[c] = 0;}}// 建图for (int i = 0; i < words.size(); i++){for (int j = i + 1; j < words.size(); j++){if(add(words[i], words[j]))return "";}}// 将度为0的放入队列for (auto &[a, b] : in){if (b == 0)q.push(a);}// 进行深度遍历while (!q.empty()){char t = q.front();q.pop();ret += t;for (auto v : edges[t]){if (--in[v] == 0)q.push(v);}}std::cout << ret;if (ret.size() == in.size()) return ret;else return "";}bool add (string& s1, string& s2){int n = min(s1.size(), s2.size());int i = 0;for (; i < n; i++){if (s1[i] != s2[i]){char a = s1[i], b = s2[i];if (!edges.count(a) | !edges[a].count(b)){edges[a].insert(b);in[b]++;}break;}}if (i == s2.size() && i < s1.size()) return true; // 处理特殊情况,示例4else return false;}
};

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

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

相关文章

【局域网投屏】sunshine和moonlight投屏/屏幕共享/扩展屏

主机是sunshine&#xff0c;客机是moonlight&#xff0c;一个太阳一个月光&#xff0c;两者真是太配啦&#xff01; 下载sunshine sunshine是服务器端&#xff0c;去以下GitHub链接下载windows端的解压缩即用版 https://github.com/LizardByte/Sunshine/releases下载完毕解压…

基于Logistic-Map混沌序列的数字信息加解密算法matlab仿真,支持对文字,灰度图,彩色图,语音进行加解密

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于Logistic-Map混沌序列的数字信息加解密算法matlab仿真,系统包含GUI操作界面&#xff0c;系统支持对文字,灰度图,彩色图,语音进行加解密。 2.测试软件版本以及…

【银河麒麟高级服务器操作系统】虚拟机服务器执行systemctl提示timeout——分析全过程及处理建议

了解更多银河麒麟操作系统全新产品&#xff0c;请点击访问 麒麟软件产品专区&#xff1a;https://product.kylinos.cn 开发者专区&#xff1a;https://developer.kylinos.cn 文档中心&#xff1a;https://documentkylinos.cn 现象描述 产品信息 产品名称 银河麒麟高级服务…

UE5学习笔记21-武器的射击功能

一、创建C类 创建武器子弹的类&#xff0c;创建生产武器子弹的类&#xff0c;创建弹壳的类&#xff0c;生产武器子弹的类的父类是武器的类 创建后如图&#xff0c;ProjectileMyWeapon类(产生子弹的类)继承自weapon类&#xff0c;Projectile(子弹的类)&#xff0c;Casing(弹壳声…

第三部分:3---环境变量

目录 什么是环境变量&#xff1f; PATH环境变量&#xff1a; 临时修改环境变量PATH&#xff1a; HOME环境变量&#xff1a; 可能使用环境变量的场景&#xff1a; 进程和环境变量的关系&#xff1a; 环境变量相关操作&#xff1a; 代码获取环境变量&#xff1a; 主函数传…

迭代器模式iterator

学习笔记&#xff0c;原文链接 https://refactoringguru.cn/design-patterns/iterator 不暴露集合底层表现形式 &#xff08;列表、 栈和树等&#xff09; 的情况下遍历集合中所有的元素

【Unity基础】如何选择Mono的.Net API版本

Edit -> Project Settings -> Player : Api Compatibility Level 在 Unity 的 Project Settings -> Player -> Other Settings 中&#xff0c;API Compatibility Level 设置决定了项目中使用的 .NET API 的兼容级别。Unity 提供了两种主要的 API 兼容级别选项&…

《论层次架构及其在软件系统中的应用》写作框架,软考高级系统架构设计师

论文真题 层次架构作为软件系统设计的一种基本模式&#xff0c;对于实现系统的模块化、可维护性和可扩展性具有至关重要的作用。在软件系统的构建过程中&#xff0c;采用层次架构不仅可以使系统结构更加清晰&#xff0c;还有助于提高开发效率和质量。因此&#xff0c;对层次架…

Jedis,SpringDataRedis

快速入门 导入依赖 <!--jedis--><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.7.0</version></dependency><!--单元测试--><dependency><groupId>org.ju…

秋招突击——算法练习——9/4——73-矩阵置零、54-螺旋矩阵、48-旋转图像、240-搜索二维矩阵II

文章目录 引言复习新作73-矩阵置零个人实现 54-螺旋矩阵个人实现参考实现 48-旋转图像个人实现参考实现 240-搜索二维矩阵II个人实现参考实现 总结 引言 秋招开展的不是很顺利&#xff0c;还是要继续准备&#xff0c;继续刷算法&#xff01;不断完善自己&#xff0c;希望能够找…

Vue实现自定义进度条占比功能 Vue自定义进度条功能

在不使用echarts等第三方插件的情况下,使用Vue实现自定义的进度条占比功能,并且是多数据可选循环的 预览图效果 首先看一下获取的后端返回的数据结构,其中每一组加起来等于 22 ,也就是说如果你自己算的话也是同理,根据 占比的数值 除以 总和 =的百分比再去渲染对应占比…

Linux连接阿里云服务器的一系列命令教程

**-p&#xff1a;**连同文件的属性一起复制过去&#xff0c;而非使用默认属性(备份常用)&#xff1b; **-d&#xff1a;**若来源档为连结档的属性(link file)&#xff0c;则复制连结档属性而非文件本身&#xff1b; **-r&#xff1a;**递归持续复制&#xff0c;用於目录的复制…

SpringBoot教程(十五) | SpringBoot集成RabbitMq(消息丢失、消息重复、消息顺序、消息顺序)

SpringBoot教程&#xff08;十五&#xff09; | SpringBoot集成RabbitMq&#xff08;消息丢失、消息重复、消息顺序、消息顺序&#xff09; RabbitMQ常见问题解决方案问题一&#xff1a;消息丢失的解决方案&#xff08;1&#xff09;生成者丢失消息丢失的情景解决方案1&#xf…

记一次Hiveserver2连接异常的解决-腾讯云-emr

原文阅读&#xff1a;【巨人肩膀社区博客分享】记一次Hiveserver2连接异常的解决-腾讯云-emr 离线任务跑的好好的&#xff0c;忽然有一天失败了&#xff0c;查看海豚上的任务执行日志发现是hiveserver2连接超时了。 查看监控发现了几个问题一个是GC变得频繁&#xff0c;另一个…

【LabVIEW学习篇 - 19】:人机界面交互设计03

文章目录 运行菜单主菜单右键快捷菜单 运行菜单 菜单是人机交互非常重要的一个途径&#xff0c;它的好处是把需要的操作隐藏起来&#xff0c;当用户需要的时候才激活&#xff0c;因此相对于把所有的操作以按钮的形式放在界面上&#xff0c;可以节省很大的空间。 菜单有两种&a…

Learn OpenGL In Qt之着色器

竹杖芒鞋轻胜马,谁怕?一蓑烟雨任平生~ 公众号&#xff1a; C学习与探索 | 个人主页&#xff1a; rainInSunny | 个人专栏&#xff1a; Learn OpenGL In Qt 文章目录 写在前面GLSL变量输入输出顶点着色器片段着色器 Uniform更多属性 自己的着色器类 关注公众号&#xff1a;…

TCP通信实现

前言 TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff09;是一种面向连接的、可靠的、基于流的通信协议。它是互联网协议栈&#xff08;TCP/IP&#xff09;中的核心协议之一&#xff0c;主要用于保证在计算机网络中可靠地传输数据。 TCP通信的基…

Android视频编辑:利用FFmpeg实现高级功能

在移动设备上进行视频编辑的需求日益增长&#xff0c;用户期望能够在智能手机或平板电脑上轻松地编辑视频&#xff0c;以满足社交媒体分享或个人存档的需求。Android平台因其广泛的用户基础和开放的生态系统&#xff0c;成为视频编辑应用的理想选择。FFmpeg&#xff0c;作为一个…

Leetcode面试经典150题-55.跳跃游戏

解法都在代码里&#xff0c;不懂就留言或者私信 class Solution {public boolean canJump(int[] nums) {/**如果就一个位置&#xff0c;你本来就在这&#xff0c;肯定可以跳到*/if(nums.length 1) {return true;}/**这个题的解题思路是遍历数组&#xff0c;如果当前位置不在之…