【LeetCode】拓扑排序——课程表 I II

news/2025/1/16 5:30:49/

拓扑排序:

AOV网:若用DAG图(有向无环图)表示一个工程,其顶点表示活动,用有向边<Vi, Vj>表示活动Vi必须先于活动Vj进行的这样一种关系,则将这种有向图称为顶点表示活动的网络,记为AOV网。在AOV网中,活动Vi是活动Vj的直接前驱,活动Vj是活动Vi的直接后继,这种前驱和后继关系具有传递性,且任何活动Vi不能以它自己作为自己的前驱或后继。

拓扑排序:在图论中,由一个有向无环图的顶点组成的序列,当且仅当满足下列条件时,称为该图的一个拓扑排序:

  • 每个顶点出现且只出现一次。
  • 若顶点A在序列中排在顶点B的前面,则在图中不存在从顶点B到顶点A的路径。

或定义为:拓扑排序是对有向无环图的顶点的一种排序,它使得若存在一条从顶点A到顶点B的路径,则在排序中顶点B出现在顶点A的后面。每个AOV网都有一个或多个拓扑排序序列。

对一个AOV网进行拓扑排序的算法有很多,下面介绍比较常用的一种方法的步骤:

  1. 从AOV网中选择一个没有前驱的顶点并输出。
  2. 从网中删除该顶点和所有以它为起点的有向边。
  3. 重复①和②直到当前的AOV网为空或当前网中不存在无前驱的顶点为止。后一种情况说明有向图中必然存在环。

如图所示为拓扑排序过程的示例。每轮选择一个入度为0的顶点并输出,然后删除该顶点和所有以它为起点的有向边,最后得到拓扑排序的结果为{1, 2, 4, 3, 5}。

实现拓扑排序:借助队列,来一次BFS

  1. 初始化:把所有入度为0的顶点加入到队列中
  2. 当队列不为空的时候
    1)拿出队头元素,加入到最终结果中
    2)删除与该元素相连的边
    3)判断与删除边相连的顶点是否入度变成0,变成0则加入到队列中

图的存储之邻接表法:

当一个图为稀疏图时,使用邻接矩阵法显然要浪费大量的存储空间,而图的邻接表法结合了顺序存储和链式存储方法,大大减少了这种不必要的浪费。

所谓邻接表,是指对图G中的每个顶点Vi建立一个单链表,第i个单链表中的结点表示依附于顶点Vi的边(对于有向图则是以顶点Vi为尾的弧),这个单链表就为顶点Vi的边表(对于有向图则称为出边表)。边表的头指针和顶点的数据信息采用顺序存储(称为顶点表),所以在邻接表中存在两种结点:顶点表结点和边表结点,如图所示。

顶点表结点由顶点域(data)和指向第一条邻接边的指针(firstarc)构成,边表(邻接表)结点由邻接点域(adjvex)和指向下一条邻接边的指针域(nextarc)构成。

无向图和有向图的邻接表的实例如图所示。

两种表示方法:

  • vector<vector<int>> edges
  • unordered_map<int, vector<int>> edges

根据题目需要可以把int换成string。

1. 课程表(中等)

class Solution {
public:bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {// 1. 准备工作unordered_map<int, vector<int>> edges; // 邻接表存图vector<int> in(numCourses); // 标记每一个顶点的入度// 2. 建图for (auto& e : prerequisites){int a = e[0], b = e[1]; // b->a的一条边edges[b].push_back(a);in[a]++;}// 3. 拓扑排序queue<int> q;// (1) 把所有入度为0的点加入到队列中for (int i = 0; i < numCourses; i++){if (in[i] == 0){q.push(i);}}// (2) BFSwhile(!q.empty()){int cur = q.front();q.pop();for (auto& a : edges[cur]){in[a]--;if (in[a] == 0){q.push(a);}}}// 4. 判断是否有环for (int i = 0; i < numCourses; i++){if (in[i])return false;}return true;}
};

2. 课程表 II(中等)

class Solution {
public:vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {// 1. 准备工作vector<vector<int>> edges(numCourses); // 邻接表存图vector<int> in(numCourses); // 标记每一个顶点的入度// 2. 建图for (auto& e : prerequisites){int a = e[0], b = e[1]; // b->a的一条边edges[b].push_back(a);in[a]++;}// 3. 拓扑排序queue<int> q;vector<int> ans;// (1) 把所有入度为0的点加入到队列中for (int i = 0; i < numCourses; i++){if (in[i] == 0){q.push(i);}}// (2) BFSwhile(!q.empty()){int cur = q.front();q.pop();ans.push_back(cur);for (auto& a : edges[cur]){in[a]--;if (in[a] == 0){q.push(a);}}}// 4. 判断是否有环if (ans.size() == numCourses)return ans;return {};}
};

http://www.ppmy.cn/news/1446826.html

相关文章

JAVA面试专题-Redis

你在最近的项目中哪些场景使用了Redis 缓存 缓存穿透 缓存穿透&#xff1a;查询一个不存在的数据&#xff0c;mysql查询不到数据也不好直接写入缓存&#xff0c;导致每次请求都查数据库。 解决方案一&#xff1a;缓存空数据&#xff0c;即使查询返回的数据为空&#xff0c;也把…

制定语音芯片的语音识别指令时需要关注的内容

背景 最近定义设备识别的语音指令以及对应的语音反馈。虽然语音控制在软件里只是很小的一块功能&#xff0c;但也不能太马虎。新人入坑就要学习&#xff0c;学习前人的经验规避问题&#xff0c;最后总结经验给后人&#xff0c;给未来的自己。好记性不如烂笔头~ 下面一些问题是…

vscode 检查更新 没有检查更新按钮

vscode 检查更新 没有检查更新按钮 1、问题描述2、问题分析3、解决方法 1、问题描述 今天在使用vscode写markdown文档时&#xff0c;需要粘贴图片到markdown文档中&#xff0c;结果无法粘贴进来&#xff0c;显示如下&#xff1a;只粘贴了image.png这几个字。 2、问题分析 搜索…

Mybatis.net + Mysql

项目文件结构 NuGet下载Mybatis.net相关包&#xff1a;IBatisNet 安装完成后&#xff0c;会显示在&#xff0c;在已安装页面。同时&#xff0c;在管理器中的引用列表中&#xff0c;会多出来两个引用文件 IBatisNet.CommonIBatisNet.DataMapper 安装 Mysql.data。 注意&#xff…

Spring Boot微服务架构实战

Spring Boot微服务架构实战是一个涉及到多个关键技术和步骤的过程&#xff0c;以下是关于其详细论述&#xff1a; 一、微服务架构概述 微服务架构是一种将单个应用程序拆分为一组小的服务的方法&#xff0c;每个服务都运行在其独立的进程中&#xff0c;服务与服务之间通过轻量…

Java将文件目录转成树结构

在实际开发中经常会遇到返回树形结构的场景&#xff0c;特别是在处理文件系统或者是文件管理系统中。下面就介绍一下怎么将文件路径转成需要的树形结构。 在Java中&#xff0c;将List<String>转换成树状结构&#xff0c;需要定义一个树节点类&#xff08;TreeNode&#…

关于发布 npm 包镜像库,马上 pnpm 安装报未找到版本的问题?

关于发布 npm 包镜像库&#xff0c;马上 pnpm 安装报未找到版本的问题&#xff1f; 背景&#xff1a;我们在发布共有 npm 包时&#xff0c;npm 官方镜像发布成功&#xff0c;但是淘宝源下载却没有找到刚发布的版本&#xff0c;下面是我遇到问题心路历程 文章目录 关于发布 npm…

宠物领养|基于SprinBoot+vue的宠物领养管理系统(源码+数据库+文档)

宠物领养目录 基于Spring Boot的宠物领养系统的设计与实现 一、前言 二、系统设计 三、系统功能设计 1前台 1.1 宠物领养 1.2 宠物认领 1.3 教学视频 2后台 2.1宠物领养管理 2.2 宠物领养审核管理 2.3 宠物认领管理 2.4 宠物认领审核管理 2.5 教学视频管理 四、…