算法沉淀——BFS 解决拓扑排序(leetcode真题剖析)

在这里插入图片描述

算法沉淀——BFS 解决拓扑排序

  • 01.课程表
  • 02.课程表 II
  • 03.火星词典

Breadth-First Search (BFS) 在拓扑排序中的应用主要是用来解决有向无环图(DAG)的拓扑排序问题。拓扑排序是对有向图中所有节点的一种线性排序,使得对于每一条有向边 (u, v),节点 u 在排序中都出现在节点 v 的前面。如果图中存在环路,则无法进行拓扑排序。

BFS 解决拓扑排序的步骤如下:

  1. 统计每个节点的入度(in-degree),即指向该节点的边的数量。
  2. 将所有入度为 0 的节点加入队列。
  3. 对于每个入度为 0 的节点,依次出队,更新其相邻节点的入度,将入度变为 0 的节点加入队列。
  4. 重复步骤 3 直到队列为空。

如果最终遍历过的节点数等于图中的节点数,说明图是有向无环图,可以得到一个拓扑排序。

01.课程表

题目链接:https://leetcode.cn/problems/course-schedule/

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

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

  • 例如,先修课程对 [0, 1] 表示:想要学习课程 0 ,你需要先完成课程 1

请你判断是否可能完成所有课程的学习?如果可以,返回 true ;否则,返回 false

示例 1:

输入:numCourses = 2, prerequisites = [[1,0]]
输出:true
解释:总共有 2 门课程。学习课程 1 之前,你需要完成课程 0 。这是可能的。

示例 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] 中的所有课程对 互不相同

思路

这里我们可以采用容器模拟邻接矩阵或者邻接表来进行拓扑排序,判断这个图是否有环的方式来解决这个问题

代码

class Solution {
public:bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {unordered_map<int,vector<int>> edges;vector<int> in(numCourses,0);for(vector<int>& e:prerequisites){int a=e[0],b=e[1];edges[b].push_back(a);in[a]++;}queue<int> q;for(int i=0;i<numCourses;++i) if(in[i]==0) q.push(i);while(!q.empty()){int t=q.front();q.pop();for(int e:edges[t]){in[e]--;if(in[e]==0) q.push(e);}}for(int i:in) if(i) return false;return true;}
};
  1. 使用一个哈希表 edges 存储有向图的边,其中 edges[b] 表示节点 b 指向的所有节点。
  2. 使用数组 in 记录每个节点的入度。初始化时,将所有节点的入度设为 0。
  3. 遍历先修课程的关系,构建有向图并更新入度数组。
  4. 将入度为 0 的节点加入队列 q
  5. 使用 BFS 进行拓扑排序,从入度为 0 的节点开始,依次出队,并将其邻接节点的入度减 1。如果邻接节点的入度减为 0,将其加入队列。
  6. 如果最终所有节点的入度都为 0,说明图中不存在环,可以完成所有课程,返回 true;否则,返回 false

02.课程表 II

题目链接:https://leetcode.cn/problems/course-schedule-ii/

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

  • 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示:[0,1]

返回你为了学完所有课程所安排的学习顺序。可能会有多个正确的顺序,你只要返回 任意一种 就可以了。如果不可能完成所有课程,返回 一个空数组

示例 1:

输入:numCourses = 2, prerequisites = [[1,0]]
输出:[0,1]
解释:总共有 2 门课程。要学习课程 1,你需要先完成课程 0。因此,正确的课程顺序为 [0,1] 。

示例 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:

输入:numCourses = 1, prerequisites = []
输出:[0]

思路

总体思路和上面一致,我们只需要在每次将入度为0的点顺序保存即为拓扑排序的顺序。

代码

class Solution {
public:vector<int> findOrder(int numCourses, vector<vector<int>>& prerequisites) {unordered_map<int,vector<int>> edges;vector<int> in(numCourses,0);for(vector<int>& e:prerequisites){int a=e[0],b=e[1];edges[b].push_back(a);in[a]++;}queue<int> q;vector<int> ret;for(int i=0;i<numCourses;++i) if(in[i]==0){q.push(i);ret.push_back(i);} while(!q.empty()){int t=q.front();q.pop();for(int e:edges[t]){in[e]--;if(in[e]==0){ q.push(e);ret.push_back(e);    }}}for(int i:in) if(i) return {};return ret;}
};
  1. 使用一个哈希表 edges 存储有向图的边,其中 edges[b] 表示节点 b 指向的所有节点。
  2. 使用数组 in 记录每个节点的入度。初始化时,将所有节点的入度设为 0。
  3. 遍历先修课程的关系,构建有向图并更新入度数组。
  4. 将入度为 0 的节点加入队列 q,同时将这些节点加入结果数组 ret 中。
  5. 使用 BFS 进行拓扑排序,从入度为 0 的节点开始,依次出队,并将其邻接节点的入度减 1。如果邻接节点的入度减为 0,将其加入队列和结果数组。
  6. 如果最终所有节点的入度都为 0,说明图中不存在环,返回拓扑排序结果;否则,返回空数组表示无法完成拓扑排序

03.火星词典

题目链接:https://leetcode.cn/problems/Jf1JuT

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

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

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

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

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

示例 1:

输入:words = ["wrt","wrf","er","ett","rftt"]
输出:"wertf"

示例 2:

输入:words = ["z","x"]
输出:"zx"

示例 3:

输入:words = ["z","x","z"]
输出:""
解释:不存在合法字母顺序,因此返回 "" 。

提示:

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

思路

将题意搞清楚之后,这道题就变成了判断有向图时候有环,可以用拓扑排序解决。
如何搜集信息(如何建图):
a. 两层for循环枚举出所有的两个字符串的组合;
b. 然后利用指针,根据字典序规则找出信息。

  1. 使用哈希表 edges 存储字母之间的顺序关系,其中 edges[a] 表示字母 a 后面可以跟随的字母集合。
  2. 使用哈希表 in 记录每个字母的入度,即有多少字母在它之前。
  3. 使用布尔变量 cheak 标记是否出现了无效的字母顺序。
  4. 定义 add 函数,该函数比较两个单词 s1s2,找到它们第一个不相同的字母,然后将这个字母的顺序关系添加到 edges 中。如果 s2s1 的前缀,则将 cheak 设置为 true
  5. 在构建字母之间的顺序关系时,遍历相邻的两个单词,调用 add 函数,如果 cheaktrue,则直接返回空字符串。
  6. 使用队列 q 存储入度为 0 的字母,初始化队列时将所有入度为 0 的字母加入。
  7. 使用 BFS 进行拓扑排序,不断将入度为 0 的字母出队,并将其后面可以跟随的字母的入度减 1。将入度为 0 的字母加入结果字符串 ret 中。
  8. 最后检查所有字母的入度是否都为 0,如果不为 0,则说明有环,返回空字符串;否则,返回结果字符串 ret

代码

class Solution {unordered_map<char,unordered_set<char>> edges;unordered_map<char,int> in;bool cheak=false;void add(string& s1,string& s2){int n=min(s1.size(),s2.size());int i=0;while(i<n){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;}i++;}if(i==s2.size()&&i<s1.size()) cheak=true;}
public:string alienOrder(vector<string>& words) {for(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(words[i],words[j]);if(cheak) return "";}queue<char> q;for(auto& [a,b]:in)if(b==0) q.push(a);string ret;while(!q.empty()){char t=q.front();q.pop();ret+=t;for(char ch:edges[t])if(--in[ch]==0) q.push(ch);}for(auto& [a,b]:in) if(b) return "";return ret;}
};

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

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

相关文章

Recorder 实现语音录制并上传到后端(兼容PC和移动端)

Recorder 首页&#xff1a;https://github.com/xiangyuecn/Recorder 一、安装 npm install recorder-core二、代码部分 1. HTML页面 <template><div><el-inputv-model"ttsText"type"textarea"placeholder"请输入内容"><…

外汇天眼:进Goccfx投资群前还好好的,踢出群后本金都没了

在外汇诈骗中&#xff0c;许多骗局都是以“拉群荐股”的方式&#xff0c;将一个个无辜的外汇投资者拽入虚假的外汇平台&#xff0c;投资者一旦进群&#xff0c;结果往往是被反向喊单而爆仓亏损。还有更过分的&#xff0c;就是诈骗分子利用投资者急于挽回损失的心理&#xff0c;…

YOLOv8-Openvino和ONNXRuntime推理【CPU】

1 环境&#xff1a; CPU&#xff1a;i5-12500 2 安装Openvino和ONNXRuntime 2.1 Openvino简介 Openvino是由Intel开发的专门用于优化和部署人工智能推理的半开源的工具包&#xff0c;主要用于对深度推理做优化。 Openvino内部集成了Opencv、TensorFlow模块&#xff0c;除此…

前端|Day3:CSS基础(黑马笔记)

Day3:CSS基础 目录 Day3:CSS基础一、CSS初体验二、CSS引入方式三、选择器1.标签选择器2.类选择器3.id选择器4.通配符选择器 四、盒子尺寸和背景色五、文字控制属性1.字体大小2.字体样式&#xff08;是否倾斜&#xff09;3.行高单行文字垂直居中 4.字体族5.font复合属性6.文本缩…

自适应网站建站源码系统 带完整的安装代码包以及搭建教程

在当今数字化时代&#xff0c;拥有一个功能全面且能够适应不同设备的网站对于企业和个人来说至关重要。罗峰给大家分享一款全新的自适应网站建站源码系统&#xff0c;它不仅提供了完整的安装代码包&#xff0c;还附带了详细的搭建教程&#xff0c;帮助用户轻松构建出具有响应式…

Atcoder ABC340 C - Divide and Divide

Divide and Divide&#xff08;分而治之&#xff09; 时间限制&#xff1a;2s 内存限制&#xff1a;1024MB 【原题地址】 所有图片源自Atcoder&#xff0c;题目译文源自脚本Atcoder Better! 点击此处跳转至原题 【问题描述】 【输入格式】 【输出格式】 【样例1】 【样例…

Windows制作Ubuntu的U盘启动盘

概要&#xff1a; 本篇演示在Windows10中制作Ubuntu22.04的U盘启动盘 一、下载Ubuntu22.04的iso文件 在浏览器中输入https://ubuntu.com去Ubuntu官网下载Ubuntu22.04的iso文件 二、下载Ultraiso 在浏览器中输入https://www.ultraiso.com进入ultraiso官网 点击FREE TRIAL&a…

com.alibaba.fastjson.JSONException: toJSON error的原因

问题&#xff1a; 导出接口报错&#xff0c;显示json格式化异常 发现问题&#xff1a; 第一个参数为HttpResponse,转换成json的时候报错 修改方法&#xff1a; 1.调换两个参数的位置 2.在aop判断里边 把ServletAPI过滤掉 Before("excudeWebController()")pub…

洛谷C++简单题小练习day12—寻找最小值小程序

day12--寻找最小值--2.16 习题概述 题目描述 给出 n 和 n 个整数 ai​&#xff0c;求这 n 个整数中最小值是什么。 输入格式 第一行输入一个正整数 n&#xff0c;表示数字个数。 第二行输入 n 个非负整数&#xff0c;表示 1,2…a1​,a2​…an​&#xff0c;以空格隔开。 …

【医学大模型 补全主诉】BioGPT + LSTM 自动补全医院紧急部门主诉

BioGPT LSTM 自动补全医院紧急部门主诉 问题&#xff1a;针对在紧急部门中自动补全主诉的问题子问题1: 提高主诉记录的准确性子问题2: 加快主诉记录的速度子问题3: 统一医疗术语的使用子问题4: 减少打字错误和误解子问题5: 提高非特定主诉的处理能力 解法数据预处理神经网络方…

【软考问题】-- 3 - IT知识 - 信息系统治理

一、基础问题 问题1:IT治理主要目标包括哪三个方面? 1⃣️与业务目标一致2⃣️有效利用信息与数据资源3⃣️风险管理问题2:IT治理的管理层次大致可分为三层是什么? (1)最高管理层(2)执行管理层(3)业务与服务执行层问题3:IT 治理和谐内容有哪些? a.组织职责

力扣145 二叉树的后序遍历 Java版本

文章目录 题目描述递归解法代码 非递归解法思路代码 题目描述 给你一棵二叉树的根节点 root &#xff0c;返回其节点值的 后序遍历 。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[3,2,1] 示例 2&#xff1a; 输入&#xff1a;root [] 输出…

Linux【动静态库】

目录 1.软硬链接 1.1软硬链接的语法 1.2理解软硬链接 1.3目录文件的硬链接 1.4应用场景 1.5ACM时间 2.动静态库 2.1认识库 3.制作静态库 3.1静态库打包 3.2静态库的使用 4.制作动态库 4.1动态库打包 4.2动态库的链接使用 4.3动态库的链接原理 总结&#xff1…

论文阅读-基于动态权重的一致性哈希微服务负载均衡优化

论文名称&#xff1a;基于动态权重的一致性哈希微服务负载均衡优化 摘要 随着互联网技术的发展&#xff0c;互联网服务器集群的负载能力正面临前所未有的挑战。在这样的背景下&#xff0c;实现合理的负载均衡策略变得尤为重要。为了达到最佳的效率&#xff0c;可以利用一致性…

【数据结构】每天五分钟,快速入门数据结构(一)——数组

目录 一.初始化语法 二.特点 三.数组中的元素默认值 四.时间复杂度 五.Java中的ArrayList类 可变长度数组 1 使用 2 注意事项 3 实现原理 4 ArrayList源码 5 ArrayList方法 一.初始化语法 // 数组动态初始化&#xff08;先定义数组&#xff0c;指定数组长度&#xf…

AUTOSAR CP--chapter7从CAN网络学习Autosar通信

从CAN网络学习Autosar通信 前言缩写词CAN通信在AUTOSAR架构中的传输上位机配置 第六章总结&#xff1a;学习了如何使用工具的自动配置功能&#xff0c;位我们生成系统描述中部分ecu的BSW模块配置&#xff0c;但是自动配置的功能虽然为我们提供了极大的便利&#xff0c;我们仍然…

专145+总420+哈尔滨工业大学803信号与系统和数字逻辑电路考研经验哈工大电子信息与通信,真题,大纲,参考书。

自从高考失利没有考入哈工大&#xff0c;一直带着遗憾&#xff0c;今年初试专业课803信号与系统和数字逻辑电路145&#xff0c;总分420顺利圆满哈工大&#xff0c;了却了一块心病&#xff0c;回看这一年的复习起起落落&#xff0c;心中的那块初心&#xff0c;让我坚持到了上岸&…

算法通关村-----继续看回溯问题

复原IP地址 问题描述 有效 IP 地址 正好由四个整数&#xff08;每个整数位于 0 到 255 之间组成&#xff0c;且不能含有前导 0&#xff09;&#xff0c;整数之间用 ‘.’ 分隔。 例如&#xff1a;“0.1.2.201” 和 “192.168.1.1” 是 有效 IP 地址&#xff0c;但是 “0.011.…

ElasticSearch之Index Template 和Dynamic Template

写在前面 在ElasticSearch之Mapping 一文中我们一起看了es的dynamic mapping机制&#xff0c;通过该机制允许我们不需要显式的定义mapping信息&#xff0c;而是es根据插入的文档值来自动生成 &#xff0c;比如插入如下的文档&#xff1a; {"firstName": "Chan…

前端新手Vue3+Vite+Ts+Pinia+Sass项目指北系列文章 —— 第十一章 基础界面开发 (组件封装和使用)

前言 Vue 是前端开发中非常常见的一种框架&#xff0c;它的易用性和灵活性使得它成为了很多开发者的首选。而在 Vue2 版本中&#xff0c;组件的开发也变得非常简单&#xff0c;但随着 Vue3 版本的发布&#xff0c;组件开发有了更多的特性和优化&#xff0c;为我们的业务开发带…