【基础算法总结】BFS_拓扑排序问题

目录

  • 一, 拓扑排序简介
    • 1. 有向无环图(DAG图)
    • 2. AOV 网
    • 3. 拓扑排序
    • 4. 如何实现拓扑排序
  • 二,算法原理和代码实现
    • 207.课程表
    • 201.课程表II
    • LCR114.火星词典
  • 三,算法总结

一, 拓扑排序简介

1. 有向无环图(DAG图)

在这里插入图片描述

入度:针对一个点,有多少条边指向它
出度:针对一个点,有多少条边从这个点出去

如上图:1顶点的入度是0,出度是2。2顶点的入度是2,出度是1。3顶点的入度是1,出度是2…

2. AOV 网

在有向无环图中,用顶点来表示一个活动,用边来表示活动顺序的图结构如下实例:

在这里插入图片描述

3. 拓扑排序

通俗的来说,就是在AOV网中找到做事情的先后顺序。拓扑排序的结果是不唯一的

在这里插入图片描述

那如何进行排序呢?

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

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

4. 如何实现拓扑排序

借助队列,来一次bfs即可

在这里插入图片描述

二,算法原理和代码实现

207.课程表

在这里插入图片描述

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/ffcbe7ce0af74900a08c583b33f9e8c6.png

算法原理:

这道题可以抽象成拓扑排序问题。题目是问能否完成课程学习,其实就是问是否存在拓扑序列,也相当于问这个有向图中是否有环,若有环,则不能完成,否则可以完成

下一个重点是如何建图?

拓扑建图一般有两种方式,邻接矩阵和邻接表,如何选择就要看数据的稠密程度。数据稀疏就用邻接表,稠密就用邻接矩阵。这里只介绍邻接表。
在这里插入图片描述

细节/技巧问题:

(1) 根据拓扑排序的流程,我们还需要知道每个顶点的入度是多少,只有入度为0的才入队列。所以还需要建立一个数组记录入度值
(2) 在进行最后的判断时,是用点的入度值来判断的。如果存在拓扑序列,则每个点的入度值肯定为0,否则就不存在

代码实现:
这里我们使用的是unordered_map建立邻接表

class Solution 
{
public:bool canFinish(int n, vector<vector<int>>& prerequisites) {unordered_map<int, vector<int>> edges; // 邻接表存图vector<int> in(n); // 记录每个顶点的入度// 1.建图for(auto& e : prerequisites){int a = e[0], b = e[1]; // b --> aedges[b].push_back(a); // 一个顶点后面跟着的几个顶点in[a]++; // a的入度+1}// 2.拓扑排序// (1). 把所有入度为0顶点的加入队列中queue<int> q;for(int i = 0; i < n; i++){if(in[i] == 0)q.push(i); // 这里要注意区分,i是指那个顶点,in[i]是该顶点对应的入度值}// (2).bfswhile(q.size()){int t = q.front();q.pop();// 找到这个入度为0顶点所指向的其他顶点,修改它们的入度值// edges[t]是那个数组,用范围for进行遍历,数组里面存的就是那些顶点for(int a : edges[t]){in[a]--;if(in[a] == 0) q.push(a);}}// 3.判断是否有环// 如果不成环,说明已经找出了顺序,入度一定为0,否则就成环了for(int i = 0; i < n; i++)if(in[i]) return false;return true;}
};

201.课程表II

在这里插入图片描述
在这里插入图片描述

算法原理:

这道题和第一题基本一模一样,唯一不同的是如果可以完成课程,本题最后要返回拓扑序列,否则就返回空数组

细节/技巧问题:

最后检查是否存在拓扑序列时要用那个返回数组的元素个数来判断如果存在拓扑序列,则元素个数==课程数,否则就不存在

代码实现:

方式1:哈希表

class Solution 
{
public:vector<int> findOrder(int n, vector<vector<int>>& prerequisites) {unordered_map<int, vector<int>> edges; // 邻接表存图vector<int> in(n); // 记录每个点的入度// 建图for(auto& e : prerequisites){int a = e[0], b = e[1];edges[b].push_back(a);in[a]++;}// 拓扑排序// (1)把入度为0的点入队列queue<int> q;for(int i = 0; i < n; i++){if(in[i] == 0)q.push(i);}vector<int> ret;// (2) bfswhile(q.size()){int t = q.front();q.pop();ret.push_back(t);for(int a : edges[t]){in[a]--; // 把那条边删除if(in[a] == 0) q.push(a);}}// 检查if(ret.size() == n) return ret;else return {};}
};

方式2:二维数组

class Solution 
{
public:vector<int> findOrder(int n, vector<vector<int>>& prerequisites) {vector<vector<int>> edges(n); // 邻接表存图vector<int> in(n); // 记录每个点的入度// 建图for(auto& e : prerequisites){int a = e[0], b = e[1];edges[b].push_back(a);in[a]++;}// 拓扑排序// (1)把入度为0的点入队列queue<int> q;for(int i = 0; i < n; i++){if(in[i] == 0)q.push(i);}vector<int> ret;// (2) bfswhile(q.size()){int t = q.front();q.pop();ret.push_back(t);for(int a : edges[t]){in[a]--; // 把那条边删除if(in[a] == 0) q.push(a);}}// 检查if(ret.size() == n) return ret;else return {};}
};

LCR114.火星词典

在这里插入图片描述在这里插入图片描述

算法原理:

这道题无论是理解题意还是代码实现都确实很难。首先来理解题意,题目的意思是通过它给出的字符串数组,把每个字符串进行比较,当遇到一个字符不同时,就停止比较,此时前一个字符就比后一个字符的字典序低
在这里插入图片描述

这道题可以抽象为拓扑排序问题。就拿示例1来说w–>e说明w在e的前面,就是 w<e
在这里插入图片描述
所以题目要求的新的字典序就是拓扑序列

细节/技巧问题:

(1) 建图。这道题的顶点是字符,所以只能用哈希表建图,但是由于在字符串比较的过程中会出现冗余现象,比如1,3进行比较,得出w–> e,1,4进行比较,也是w–> e。为了避免这种现象可以再嵌套一个哈希。所以最终建图使用的是 hash<char, hasn< char >>

(2) 统计入度信息。因为这里的字符串不一定有26个字符,所以不方便用 int[26] 的数组统计入度。可以使用哈希表 hash< char, int >记录每个顶点的入度值,但是这里的哈希表必须要初始化

(3) 还有一种特殊情况就是 abc 和 ab 进行比较的时候,这是不合法的,直接返回空串

代码实现:

class Solution 
{unordered_map<char, unordered_set<char>> edges; // 邻接表建图unordered_map<char, int> in; // 记录每个顶点对应的入度bool cheak; // 处理特殊情况
public:string alienOrder(vector<string>& words) {// 建图 + 初始化入度哈希表为0for(auto& s : words)for(auto ch : s)in[ch] = 0;int n = words.size();for(int i = 0; i < n; i++){for(int j = i + 1; j < n; j++){// add函数的作用:用边和点建图,判断特殊情况add(words[i], words[j]);if(cheak) return "";}}// 拓扑排序queue<char> q;// (1)把入度为0的入队列for(auto& [a, b] : in)if(b == 0)q.push(a);// (2)bfsstring ret;while(q.size()){char t = q.front();q.pop();ret += t;// 该点指向的点入度-1for(char e : edges[t]){if(--in[e] == 0) q.push(e);}}// 判断是否成环for(auto& [a, b] : in)if(b != 0) return "";return ret;}void 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]; // a --> b// a这点没有检查过或是a检查过,a指向的点没有检查过if(!edges.count(a) || !edges[a].count(b)){edges[a].insert(b);in[b]++;}break; // 第一次发现不同就停止}}// 处理 abc ab 这种特殊情况if(i == s2.size() && i < s1.size()) cheak = true;}
};

三,算法总结

使用拓扑排序的算法解决问题时,首先我认为最重要的一点是能否把题干转换成有向无环图

接着就是建图问题,使用哪种容器存点和边,这里我们介绍了邻接表的两种方式:二维数组和哈希表。但是并不是只能用这两个,而是要根据题目灵活的选取嵌套

建完图后就是拓扑排序的主体,首先把入度为0的顶点入队列,再使用bfs删除取出顶点的那些边,在把它指向的顶点入度-1

最后判断结果的时候要么问是否存在拓扑排序要么就是返回拓扑序列,其实本质都是要判断是否成环如果是第一种,就直接用入度值进行判断,存在拓扑排序,入度值一定都是0,如果是第二种,不仅要判断入度值,还要在bfs中把每次取出的队头元素用容器存起来

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

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

相关文章

详解GPU服务器与普通服务器之间的差异

GPU服务器与普通服务器之间的差异&#xff0c;犹如赛车与家用车的对比&#xff0c;不仅在于表面的速度与力量&#xff0c;更深入到其核心技术与应用场景的广泛适应性。以下是对这些差异的深度剖析与美化呈现&#xff1a; 一、硬件配置&#xff1a;架构的革新 普通服务器&#…

Linux下的MySQL8.0报错:[Err]1055

Linux下的MySQL8.0报错&#xff1a;[Err]1055 报错信息解决办法 报错信息 在Linux环境下的MySQL里执行SQL语句报如下错误&#xff1a;[Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated column information_schema.PROFIL…

Linux下使用crontab配置定时任务

文章目录 Linux使用crontab安装crontab启动crontab查看定时任务创建定时任务配置案例配置语法位置含义符号含义 注意 取消定时任务 Linux使用crontab crontab为Linux下的计划任务程序&#xff0c;对应的服务为crond。crond是一个守护进程&#xff0c;每分钟会定期检查是否有要…

涨幅超过了90%,心动网络股价成V字后,TapTap找到流量源了吗?

心动公司发布了截至2024年6月30日止六个月的中期业绩。 在2024年上半年&#xff08;24H1&#xff09;&#xff0c;公司实现总营收22.21亿元&#xff0c;较去年同期增长了26.7%。归属于母公司的净利润达到2.05亿元&#xff0c;同比激增127.4%。经调整后&#xff0c;归属于母公司…

# 利刃出鞘_Tomcat 核心原理解析(十)-- Tomcat 性能调优--1

利刃出鞘_Tomcat 核心原理解析&#xff08;十&#xff09;-- Tomcat 性能调优–1 一、Tomcat专题 - Tomcat性能调优 - 性能测试 1、tomcat 性能测试&#xff1a; 对于系统性能&#xff0c;用户最直观的感受就是系统的加载和操作时间&#xff0c;即用户执行某项操作的耗时。从…

10 先序遍历创建二叉树

这个代码是使用手动输入的方式创建二叉树 比较直观 #include "stdio.h" #include "stdlib.h"typedef int ElemType; typedef struct node {ElemType data;struct node *lchild;struct node *rchild; } Node;Node *create_node(int value) {Node *node (N…

HTTP代理支持UDP协议吗?

在网络通信中&#xff0c;HTTP代理和UDP协议是两个常见但功能和用途不同的技术。本文将详细探讨HTTP代理是否支持UDP&#xff0c;以及在什么情况下可以实现两者的结合。 HTTP代理的基本概念 HTTP代理是一种代理服务器&#xff0c;用于处理HTTP请求和响应。它在客户端和目标服…

element table 表格 span-method 某一列进行相同合并 支持树结构表格

须知 这是 vue2 版本&#xff0c;不过理论上 vue3 也能参考使用 可以直接打开 codepen 查看代码 效果图 代码 打不开 codepen 或者codepen 失效&#xff0c;查看下面代码参考 <script src"//unpkg.com/vue2/dist/vue.js"></script> <script src&…

驭势科技研究成果入选学术顶会IROS 2024

近日&#xff0c;驭势科技团队关于自动驾驶车辆定位算法的最新研究成果《LiDAR-based HD Map Localization using Semantic Generalized ICP with Road Marking Detection》&#xff0c;创造性地解决了基于LiDAR的实时路标检测和高精地图配准所带来的挑战&#xff0c;成功入选国…

第九届“创客中国”生成式人工智能中小企业创新创业大赛招商推介圆满落幕

金秋九月,丹桂飘香。9月2日晚,第九届“创客中国”生成式人工智能(AIGC)中小企业创新创业大赛招商推介会在南昌高新区艾溪湖畔成功举办。南昌市政府副秘书长、办公室党组成员陈吉炜出席并致辞。市中小企业局党组书记、市工信局党组书记、局长骆军出席。南昌高新区党工委委员、管…

CMU 10423 Generative AI:lec2

文章目录 1 概述2 部分摘录2.1 噪声信道模型&#xff08;Noisy Channel Models&#xff09;主要内容&#xff1a;公式解释&#xff1a;应用举例&#xff1a; 2.2 n-Gram模型1. 什么是n-Gram模型2. 早期的n-Gram模型3. Google n-Gram项目4. 模型规模与训练数据5. n-Gram模型的局…

AI科学家:自动化科研的未来之路

随着人工智能&#xff08;AI&#xff09;技术的不断进步&#xff0c;AI已经在众多领域中展现了强大的潜力&#xff0c;尤其是在科研方面的应用正在引起广泛关注。最近&#xff0c;Sakana AI与牛津大学和不列颠哥伦比亚大学联合推出了一款被称为“AI科学家”的自动化科研工具&am…

Stable Diffusion抠图插件爬坑经历,StableDiffusion实操案例(附整合资料)

今天给大家分享使用后期处理插件stable-diffusion-webui-rembg实现抠图功能。 &#x1f449;AI绘画必备工具&#x1f448; 温馨提示&#xff1a;篇幅有限&#xff0c;已打包文件夹&#xff0c;获取方式在&#xff1a;文末 &#x1f449;AI绘画基础速成进阶使用教程&#x1f…

聚铭网络入选“2024年南京市工程研究中心”认定名单

为深入实施创新驱动发展战略&#xff0c;因地制宜发展新质生产力充分发挥工程研究中心对推进产业强市的重要支撑作用&#xff0c;根据《南京市工程研究中心管理办法》&#xff0c;南京市发展和改革委员会于2024年5月组织开展了本年度南京市工程研究中心遴选工作。经企业申报、各…

[iBOT] Image BERT Pre-Training with Online Tokenizer

1、目的 探索visual tokenizer编码下的MIM&#xff08;Masked Image Modeling&#xff09; 2、方法 iBOT&#xff08;image BERT pre-training with Online Tokenizer&#xff09; 1&#xff09;knowledge distillation&#xff08;KD&#xff09; distill knowledge from the…

Linux下快速判断当前终端使用的是bash or csh

在Linux下设置环境变量的时候&#xff0c;可能你也遇到过export: Command not found一类的错误。这是因为当前终端使用的不是bash&#xff0c;如何快速判断当前终端使用的是哪种类型的shell呢&#xff1f; echo $0判断shell类型 最简单的方法就是在终端输入echo $0&#xff0…

Linux---文件(2)---文件描述符缓冲区(语言级)

目录 文件描述符 基础知识 文件描述符 对“Linux一切皆文件”的理解 文件描述符分配规则 缓冲区 刷新策略 存放位置 解释一个"奇怪的现象" 格式化输入输出 文件描述符 基础知识 在系统层面上&#xff0c;文件操作都是通过文件描述符来操作的。 程序在启…

leetcode回文链表

leetcode 回文链表 题目 题解 两种方式进行题解 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, Li…

JavaWeb JavaScript 9.正则表达式

生命的价值在于你能够镇静而又激动的欣赏这过程的美丽与悲壮 —— 24.8.31 一、正则表达式简介 正则表达式是描述字符模式的对象。正则表达式用简单的API对字符串模式匹配及检索替换&#xff0c;是对字符串执行模式匹配的强大工具。 1.语法 var pattnew RegExp(pattern,modi…

DataWorks数据质量监控方案

背景 日常的调度监控&#xff0c;可以查看实例任务的运行情况&#xff0c;对运行失败的实例进行告警&#xff0c;但是却无法对运行成功的实例进行数据质量的判断。而有些情况下&#xff0c;即使实例任务运行成功了&#xff0c;数据也仍然存在问题&#xff0c;这时候就需要对数…