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

news2025/1/19 23:16:15

在这里插入图片描述

算法沉淀——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.coloradmin.cn/o/1458147.html

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

相关文章

数据结构排序:插入排序、希尔排序、选择排序、冒泡排序、堆排序、快速排序

文章目录 插入排序希尔排序选择排序冒泡排序堆排序快速排序 插入排序 基本思想&#xff1a; 直接插入排序是一种简单的插入排序法&#xff0c;其基本思想是&#xff1a; 把待排序的值按其关键码值的大小逐个插入到一个已经排好序的有序序列中&#xff0c;直到所有的记录插入完…

matlab入门,在线编辑,无需安装matab

matlab相关教程做的很完善&#xff0c;除了B站看看教程&#xff0c;官方教程我觉得更加高效。跟着教程一步一步编辑&#xff0c;非常方便。 阅读 MATLAB 官方教程&#xff1a; MATLAB 官方教程提供了从基础到高级的教学内容&#xff0c;内容包括 MATLAB 的基本语法、数据处理…

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

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

Windows 使设置更改立即生效——并行发送广播消息

目录 前言 1 遍历窗口句柄列表 2 使用 SendMessageTimeout 发送延时消息 3 并行发送消息实现模拟广播消息 4 修改 UIPI 消息过滤器设置 5 托盘图标刷新的处理 6 完整代码和测试 本文属于原创文章&#xff0c;转载请注明出处&#xff1a; https://blog.csdn.net/qq_5907…

运筹系列89:anylogic仿真软件入门

1. agent-based simulation 这里概述一下help文档中Supply chain GIS model例子的要点&#xff1a;触发事件的agent和执行任务的agent。 在这个案例中&#xff0c;触发事件的agent是retailer&#xff0c;不断有订单生成&#xff1b;而执行任务的agent是vehicle&#xff0c;不断…

成功解决:× python setup.py egg_info did not run successfully.

执行pip install -r requirements.txt报错 错误信息如下&#xff1a; error: subprocess-exited-with-error python setup.py egg_info did not run successfully.│ exit code: 1╰─> [93 lines of output]解决办法&#xff1a; 更新 setuptools 和 pip pip install -…

比特浏览器bit_selenium3bit_selenium4使用

bit_selenium3 from selenium import webdriver from selenium.common.exceptions import TimeoutException from selenium.webdriver.common.keys import Keys from selenium.webdriver.chrome.options import Options from bit_api import *# /browser/open 接口会返回 selen…

我不允许你还不知道!这些求职常用黑话!

我不允许你还不知道&#xff01;这些求职常用黑话&#xff01; 一. HC、BG、BU、JD、OD、OT&#xff08;公司相关&#xff09;二、岗位相关1、base2、JD3、RD4、QA5、PM6、PR7、PD 三、求职或者薪资1、OC/意向书2、开奖3、泡池子4、保温5、A&#xff08;argue&#xff09;6、总…

数据库的备份模式(完全备份,增量备份,差异备份)

数据库的备份 备份原因 数据的丢失 数据的删除 备份目标 数据的一致性 数据的可用性 备份技术 物理备份/冷备份 直接复制数据库文件&#xff0c;适用于大型数据库环境&#xff0c;不受存储引擎的限制&#xff0c;但不能恢复到不同的MySQL版本。 常用的冷备份工具 ta…

电阻负载柜是什么?

电阻负载柜是用于模拟实际负载的设备&#xff0c;主要用于电力系统、电气设备和电子设备的测试、调试和维护。它通过调节电阻值来改变负载的大小&#xff0c;以满足不同场合的需求。电阻负载柜在电力系统、电气设备和电子设备的测试、调试和维护过程中发挥着重要作用。 电阻负载…

BI 数据分析,数据库,Office,可视化,数据仓库

AIGC ChatGPT 职场案例 AI 绘画 与 短视频制作 PowerBI 商业智能 68集 Mysql 8.0 54集 Oracle 21C 142集 Office 2021实战应用 Python 数据分析实战&#xff0c; ETL Informatica 数据仓库案例实战 51集 Excel 2021实操 100集&#xff0c; Excel 2021函数大全 80集 Excel 2021…

外贸人大部分都复工了吧

这几天是属于国家规定的节后上班时间&#xff0c;估计大部分人都已经开始复工了。作为粤西地区小伙伴中的一员&#xff0c;表示虽然身在广州&#xff0c;心却还在高州&#xff0c;毕竟年例在这些天才刚刚开始&#xff0c;我们那边每年最热闹的时候就是年例了&#xff01; 由于…

XCharts——Unity上最好用的免费开源图表插件!(一)基本介绍

只讲实用干货&#xff01;&#xff01;&#xff01;&#xff08;过于细节的或是未提及到的可直接问&#xff09; 目录 XCharts介绍 插件简介 插件下载 XCharts基本使用 类型介绍 1.折线图&#xff08;LineChart&#xff09; 2.柱形图&#xff08;BarChart&#xff09; …

IBM Spectrum LSF Process Manager 在共享分布式计算环境中运行和管理业务关键工作流程

IBM Spectrum LSF Process Manager 设计、记录和运行复杂的计算工作流 亮点 ● 快速创建复杂的分布式工作流 ● 开发可重复的最佳实践 ● 自信地运行关键工作流程 ● 提高流程可靠性 IBM Spectrum LSF Process Manager 使您能够设计和自动化计算或分析流程&#xff0c; 捕获…

力扣(LeetCode)数据结构练习题(2)

今天又写了两道关于链表的练习题&#xff0c;来给大家分享一下。巩固一下上一篇学到的链表知识&#xff0c;题目可以然我们更清楚的认识链表。 目录 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表 给你单链表的头结点 head &#xff0c;请…

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

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

从理论到实践:车间精益生产培训的全面应用指南

精益生产培训在车间的应用通常会通过以下几个步骤进行实践&#xff1a; 理论培训&#xff1a;首先&#xff0c;需要对车间的员工进行精益生产的基本理论培训&#xff0c;让他们理解精益生产的核心理念&#xff0c;比如价值流、流程优化、减少浪费、持续改进等。 现场诊断&am…

刚开工,就用Python兼职赚了5w!

前言 今天是节后上班第一天&#xff0c;祝大家开工大吉&#xff01; 先说个好消息&#xff1a;每年春节后&#xff0c;会迎来Python圈内兼职接单的小高潮。近期可以很轻松地&#xff0c;接到爬虫类和数据分析类的私活&#xff0c;需求大报酬高。 往年春节开工后的几天&#…

Spring Boot与LiteFlow:轻量级流程引擎的集成与应用含完整过程

点击下载《Spring Boot与LiteFlow&#xff1a;轻量级流程引擎的集成与应用含完整过程》 1. 前言 本文旨在介绍Spring Boot与LiteFlow的集成方法&#xff0c;详细阐述LiteFlow的原理、使用流程、步骤以及代码注释。通过本文&#xff0c;读者将能够了解LiteFlow的特点&#xff…

鸿蒙原生应用元服务实战-Serverless华为账户认证登录需尽快适配

一、ArkTS\API9&#xff0c;服务器端基于serverless开发的应用与元服务华为账号注册登录功能暂时是不支持的 二、3月1日后的审核要求 3月1日的时间是快到了。 三、会导致的结果 使用了ArkTS\API9&#xff0c;服务器端基于serverless开发的应用与元服务&#xff0c;如果要…