【算法】【优选算法】BFS 解决拓扑排序

【算法】【优选算法】BFS 解决拓扑排序

目录

一、拓扑排序

1.1 有向无环图(DAG图)

有向无环图:有向无环图:一个无回路的有向图,如果一个有向图无法从某个顶点出发经过若干条边回到该点,则这个图是一个有向无环图(DAG图)。

1.2 AOV 网:顶点活动图

在有向无环图的基础上,用顶点来表示一个活动,用边来表示活动执行的先后顺序。

1.3 拓扑排序

拓扑排序: 拓扑排序,找到做事的先后顺序。每次出入度为0的点,并且删除该点相连的边,排序进行。

1.4 实现拓扑排序

  1. 找出图中入度为0的点
  2. 删除与该点连接的变
  3. 重复1 2 直到没有点 或者 没有入度为0 的点。

借助队列,来一次BFS

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

二、207. 课程表

题目链接:207. 课程表

题目描述:

题目解析:

  • 给我们一个int数,代表id为 0 到 numCourses 的课程,
  • 给我们一个 prerequisites 数组,其中从后往前代表学习顺序
  • 让我们看能否排课,将课程学完,必须保证学习顺序

解题思路:

  • 我们使用二维数组List<List>,来表示图,每一个下标对应的一维数组,表示该点指向的点;
  • 我们遍历一次prerequisites数组,将最后的n-1列的值当成点,其余入该点对应的一维数组。除了n-1列,其余对应的入度数组对应下标值加一。
  • 在进行一次BFS即可
  • 注意事项:每个点只能入一次队,prerequisites可以是 [ ] 数组,在前面要排除。
    解题代码:
//O(M*N)//O(M*N)classSolution{publicbooleancanFinish(int numCourses,int[][] prerequisites){int m = prerequisites.length;if(m ==0)returntrue;int n = prerequisites[0].length;//建图List<List<Integer>> edges =newArrayList<>();for(int i =0; i < numCourses; i++){ edges.add(newArrayList<>());}Queue<Integer> queue =newLinkedList<>();//记录下标对应每个点的入度int[] in =newint[numCourses];//标记入过队的元素boolean[] flag =newboolean[numCourses];//记录入度for(int i =0; i < m; i++){for(int j =0; j < n-1; j++){//建图 edges.get(prerequisites[i][n-1]).add(prerequisites[i][j]);//统计入度 in[prerequisites[i][j]]++;}}//入度为0的点入队for(int i =0; i < numCourses; i++){if(in[i]==0){ queue.add(i); flag[i]=true;}}if(queue.isEmpty())returnfalse;//BFSwhile(!queue.isEmpty()){int tmp = queue.poll();//销毁边for(int i =0; i < edges.get(tmp).size(); i++){ in[edges.get(tmp).get(i)]--;}//入度为0的点入队for(int i =0; i < numCourses; i++){if(in[i]==0&&!flag[i]){ queue.add(i); flag[i]=true;}}}//还有入度不为0的点for(int i =0; i < numCourses; i++){if(in[i]!=0){returnfalse;}}returntrue;}}

三、210. 课程表 II

题目链接:210. 课程表 II

题目描述:

题目解析:

  • 给我们一个int数,代表id为 0 到 numCourses 的课程,
  • 给我们一个 prerequisites 数组,其中从后往前代表学习顺序
  • 让我们看能否排课,将课程学完,必须保证学习顺序,返回学习的顺序,不行就返回空数组。
    解题思路:
  • 我们使用二维数组List<List>,来表示图,每一个下标对应的一维数组,表示该点指向的点;
  • 我们遍历一次prerequisites数组,将最后的n-1列的值当成点,其余入该点对应的一维数组。除了n-1列,其余对应的入度数组对应下标值加一。
  • 在进行一次BFS即可,每次出的点都进入结果数组
  • 注意事项:
    • 我们先将结果数组初始化为 0 到 numCourses-1 ,,prerequisites可以是 [ ] 数组时直接就返回
    • 当最后执行完,我们使用一个计数器lep来标记进入结果数组的元素,最后只需要比较lep与numCourses是否一样,一样返回结果数组,不一样返回空数组。
      解题代码:
//O(M*N)//O(M*N)classSolution{publicint[]findOrder(int numCourses,int[][] prerequisites){//结果数组int[] ret =newint[numCourses];for(int i =0; i < numCourses;i++) ret[i]= i;int m = prerequisites.length;if(m ==0)return ret;int n = prerequisites[0].length;Queue<Integer> queue =newLinkedList<>();//标记数组boolean[] flag =newboolean[numCourses];//入度数组int[] in =newint[numCourses];//建图List<List<Integer>> edges =newArrayList<>();for(int i =0; i < numCourses; i++){ edges.add(newArrayList<>());}//记录入度,初始图for(int i =0; i < m; i++){for(int j =0; j < n-1; j++){ edges.get(prerequisites[i][n-1]).add(prerequisites[i][j]); in[prerequisites[i][j]]++;}}//入度为0的点入队for(int i =0; i < numCourses; i++){if(in[i]==0){ flag[i]=true; queue.add(i);}}//BFSint lep =0;while(!queue.isEmpty()){int tmp = queue.poll(); ret[lep++]= tmp;//删去该点出的边for(int i =0; i < edges.get(tmp).size(); i++){ in[edges.get(tmp).get(i)]--;}//入队for(int i =0; i < numCourses; i++){if(in[i]==0&&!flag[i]){ queue.add(i); flag[i]=true;}}}if(lep != numCourses)returnnewint[]{};return ret;}}

四、LCR 114. ⽕星词典

题目链接:LCR 114. ⽕星词典

题目描述:

题目解析:

  • 给我们一个字符串数组words,
  • 两个字符串对比来得出字母顺序,两个字符串第一个不相同的字母的顺序 等于 两个字符串在数组中的顺序,如示例一第一个字符串“wrt” 和 第二个字符串“wrf” 得出的字母顺序就是 t->f
  • 将所有的字符两两对比,得出字母顺序,不能得出线性顺序就返回空字符串“”

解题思路:

  • 两层for循环,先搜索两个规则导致的排序结果建立图,例如示例一就建立这个图
  • 根据图拓扑排序 ,得出结论
  • 细节问题: abc 和 ab,并且abc在数组中位于ab前面,这种是不合法的
    解题代码:
//O(M*N)//O(M*N)classSolution{//图Map<Character,Set<Character>> edges =newHashMap<>();//入度Map<Character,Integer> in =newHashMap<>();//标记有没有abc ab这种不合法boolean flag;publicStringalienOrder(String[] words){//初始化入度for(String s : words){for(int i =0; i < s.length(); i++){char ch = s.charAt(i); in.put(ch,0);}}//建图for(int i =0; i < words.length; i++){for(int j = i +1; j <words.length; j++){//统计两个字符串的字母顺序add(words[i], words[j]);if(flag ==true)return"";}}//拓扑排序初始化Queue<Character> queue =newLinkedList<>();for(char ch : in.keySet()){if(in.get(ch)==0) queue.add(ch);}//BFSStringBuffer ret =newStringBuffer();while(!queue.isEmpty()){char tmp = queue.poll(); ret.append(tmp);if(!edges.containsKey(tmp))continue;for(char ch : edges.get(tmp)){ in.put(ch, in.get(ch)-1);if(in.get(ch)==0){ queue.add(ch);}}}for(char ch : in.keySet()){if(in.get(ch)!=0)return"";}return ret.toString();}publicvoidadd(String a,String b){int i =0;int n =Math.min(a.length(), b.length());for(; i < n; i++){char ch1 = a.charAt(i);char ch2 = b.charAt(i);if(ch1 != ch2){//ch1 -> ch2if(!edges.containsKey(ch1)){ edges.put(ch1,newHashSet<>());}if(!edges.get(ch1).contains(ch2)){ edges.get(ch1).add(ch2); in.put(ch2,in.get(ch2)+1);}break;}}if(i == b.length()&& a.length()> i) flag =true;}}

Read more

【Spring】Spring事务和事务传播机制

【Spring】Spring事务和事务传播机制

🎬 那我掉的头发算什么:个人主页 🔥 个人专栏: 《javaSE》《数据结构》《数据库》《javaEE》 ⛺️待到苦尽甘来日 文章目录 * 事务三连 * 什么是事务 * 为什么要有事务 * 事务的操作 * Spring中事务的实现 * 准备工作 * Spring编程事务 * Spring 声明式事务 @Transactional * @Transactional详解 * rollbackFor * 事务隔离级别 * Mysql事务隔离级别 * Spring事务隔离级别 * Spring事务传播机制 * 总结 事务三连 什么是事务 事务是⼀组操作的集合, 是⼀个不可分割的操作. 事务会把所有的操作作为⼀个整体, ⼀起向数据库提交或者是撤销操作请求. 所以这组操作要么同时成功, 要么同时失败. 为什么要有事务 我们在进行程序开发时,也会有事务的需求。 比如转账操作: 第一步:A 账户 -100 元。 第二步:B 账户 +100

By Ne0inhk
构建基于 Rust 与 GLM-5 的高性能 AI 翻译 CLI 工具:从环境搭建到核心实现全解析

构建基于 Rust 与 GLM-5 的高性能 AI 翻译 CLI 工具:从环境搭建到核心实现全解析

前言 随着大语言模型(LLM)能力的飞速提升,将 AI 能力集成到终端命令行工具(CLI)中已成为提升开发效率的重要手段。Rust 语言凭借其内存安全、零成本抽象以及极其高效的异步运行时,成为构建此类高性能网络 IO 密集型应用的首选。本文将深度剖析如何使用 Rust 语言,结合智谱 AI 的 GLM-5 模型,从零构建一个支持流式输出、多语言切换及文件批处理的 AI 翻译引擎。 本文将涵盖环境配置、依赖管理、异步网络编程、流式数据处理(SSE)、命令行参数解析以及最终的二进制发布优化。 第一部分:Rust 开发环境的系统级构建 在涉足 Rust 编程之前,必须确保底层操作系统具备必要的构建工具链。Rust 虽然拥有独立的包管理器,但在链接阶段依赖于系统的 C 语言编译器和链接器,尤其是在涉及网络库(如 reqwest 依赖的 OpenSSL)

By Ne0inhk

【保姆级教程】MySQL 5.7 彻底卸载与重新安装全流程(附常见问题解决)

废话不多说,上实操!!! 一、彻底卸载旧版本MySQL(核心步骤) 彻底卸载是避免安装冲突的关键,请按顺序执行以下操作: 1. 停止所有MySQL服务 终止MySQL进程,防止文件占用: * 打开「服务」窗口:按 Win + R 输入 services.msc 回车。 * 找到含「MySQL」的服务(如 MySQL57),右键「停止」。 2. 卸载MySQL程序组件 移除所有安装的程序: * 打开「程序和功能」:按 Win + R 输入 appwiz.cpl 回车。 * 卸载所有含「MySQL」的组件(如 MySQL Server 5.7、MySQL Workbench)

By Ne0inhk
Spring Boot 数据缓存与性能优化

Spring Boot 数据缓存与性能优化

Spring Boot 数据缓存与性能优化 23.1 学习目标与重点提示 学习目标:掌握Spring Boot数据缓存与性能优化的核心概念与使用方法,包括数据缓存的定义与特点、Spring Boot与数据缓存的集成、Spring Boot与数据缓存的配置、Spring Boot与数据缓存的基本方法、Spring Boot的实际应用场景,学会在实际开发中处理数据缓存与性能优化问题。 重点:数据缓存的定义与特点、Spring Boot与数据缓存的集成、Spring Boot与数据缓存的配置、Spring Boot与数据缓存的基本方法、Spring Boot的实际应用场景。 23.2 数据缓存概述 数据缓存是Java开发中的重要组件。 23.2.1 数据缓存的定义 定义:数据缓存是一种存储机制,用于将常用数据存储在高速存储设备中,以便快速访问。 作用: * 提高应用程序的性能。 * 减少数据库的访问次数。 * 提高用户体验。 常见的数据缓存: * EhCache:Apache EhCache是一款开源的缓存库。 * Caffeine:

By Ne0inhk