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

news/2024/7/3 13:35:40 标签: leetcode, 算法, 拓扑排序, golang

题目链接:210. 课程表 II

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

例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示:[0,1] 。
返回你为了学完所有课程所安排的学习顺序。可能会有多个正确的顺序,你只要返回 任意一种 就可以了。如果不可能完成所有课程,返回 一个空数组 。
``
在这里插入图片描述
数据范围:
在这里插入图片描述

题解:从题目描述来看,很容易就知道是拓扑排序问题了,问题在于如何存图,如何解答,存图方式比较多,邻接表、邻接矩阵,解方面:遍历、搜索、以及队列都能完成该题的解答,实现方面很多时候还是会依赖一些语言特性,比如java、c++中有队列,可以将度为0的点放进队列中,每次出队一个去边,而在golang中数据结构支持相对匮乏,因此可以采用遍历或者搜索方式完成。

本次采用遍历方式,首先记录每个节点的入度,以及边的关系,遍历节点,每次选出一个度为0且未被选过的节点,然后去掉与这个节点相连的边,一共会执行numCourses次操作,当操作完后发现记录的答案中没有numCourses个节点,那么表示不能完成拓扑排序动作。

直接遍历:

func findOrder(numCourses int, prerequisites [][]int) []int {
	edges := make([][]int, numCourses, numCourses) // 存储边的关系
	for i := range edges {
		edges[i] = make([]int, numCourses, numCourses)
	}
	in := make([]int, numCourses, numCourses) // 记录入度
	for i := 0; i < len(prerequisites); i++ {
		a := prerequisites[i][0]
		b := prerequisites[i][1]
		edges[b][a] = 1 // 表示a指向b的边
		in[a]++
	}

	res := make([]int, 0, numCourses)
	// 遍历入度为0的点,然后去掉这些点相连的边
	for i := 0; i < numCourses; i++ { //共numCourses次操作,
		k := 0 // 记录当前寻找的入度为0的点
		for j := 0; j < numCourses; j++ { // 找一个度为0且未被遍历过的点
			if in[j] == 0 {
				res = append(res, j)
				in[j] = -1 // 记得标记为-1,已经找过的路径不再往下寻找
				k = j
				break
			}
		}
		for j := 0; j < numCourses; j++ {
			if edges[k][j] == 1 {
				edges[k][j] = -1 // 断开这条边
				in[j]-- //j点的入度-1
			}
		}
	}
	if len(res) != numCourses {
		return []int{}
	}

	return res
}

队列方式:

func findOrder(numCourses int, prerequisites [][]int) []int {
	edges := make([][]int, numCourses, numCourses) // 存储边的关系
	for i := range edges {
		edges[i] = make([]int, numCourses, numCourses)
	}
	in := make([]int, numCourses, numCourses) // 记录入度
	for i := 0; i < len(prerequisites); i++ {
		a := prerequisites[i][0]
		b := prerequisites[i][1]
		edges[b][a] = 1 // 表示a指向b的边
		in[a]++
	}

	queue := make([]int, 0, numCourses)
	for i := 0; i < numCourses; i++ {
		if in[i] == 0 {
			queue = append(queue, i)
			in[i] = -1
		}
	}

	res := make([]int, 0, numCourses) // 记录答案
	// 模拟一下队列
	for len(queue) > 0 {
		cur := queue[0]
		res = append(res, cur)

		queue = queue[1:] // 相当于除去这个元素

		// 从cur这个节点开始出发,断边
		for i := 0; i < numCourses; i++ {
			if edges[cur][i] == 1 { // 如果有边,则减少入度
				in[i]--
				edges[cur][i] = -1 // 断开这条边
				// 如果没有依赖边了,加入队列中
				if in[i] == 0 {
					queue = append(queue, i)
				}
			}
		}
	}

	if len(res) != numCourses {
		return []int{}
	}

	return res
}

http://www.niftyadmin.cn/n/5016427.html

相关文章

【雷达原理】雷达信号级建模与仿真

目录 前言一、LFMCW信号概述1.1 优点1.2 缺点 二、LFMCW信号模型2.1 发射信号模型2.2 接收信号模型2.3 信号混频 三、MATLAB仿真3.1 仿真结果3.2 代码 四、参考文献 前言 雷达信号形式多种多样&#xff0c;按照雷达的体制进行分类&#xff0c;有脉冲雷达和连续波雷达。脉冲雷达…

微信小程序开发教学系列(2)- 抖音小程序开发基础

2.1 抖音小程序的基本组成部分 抖音小程序的目录结构非常简单&#xff0c;主要包含以下几个核心文件和文件夹&#xff1a; app.json 文件&#xff1a;用于配置小程序的全局配置&#xff0c;包括窗口样式、页面路径、网络请求设置等等。pages 文件夹&#xff1a;用于存放所有的…

9. xaml ComboBox控件

1.运行图像 2.运行源码 a.Xaml源码 <Grid Name="Grid1"><!--IsDropDownOpen="True" 默认就是打开的--><ComboBox x:Name="co

2023高教社杯数学建模国赛B题思路解析+代码+论文

下文包含&#xff1a;2023高教社杯数学建模国赛B题思路解析代码参考论文等及如何准备数学建模竞赛&#xff08;7号比赛开始后逐步更新&#xff09; C君将会第一时间发布选题建议、所有题目的思路解析、相关代码、参考文献、参考论文等多项资料&#xff0c;帮助大家取得好成绩。…

vue基础知识七:SPA首屏加载速度慢的怎么解决?

一、什么是首屏加载 首屏时间&#xff08;First Contentful Paint&#xff09;&#xff0c;指的是浏览器从响应用户输入网址地址&#xff0c;到首屏内容渲染完成的时间&#xff0c;此时整个网页不一定要全部渲染完成&#xff0c;但需要展示当前视窗需要的内容 首屏加载可以说…

【算法专题突破】双指针 - 无重复字符的最长子串(10)

目录 1. 题目解析 2. 算法原理 3. 代码编写 写在最后&#xff1a; 1. 题目解析 题目链接&#xff1a;3. 无重复字符的最长子串 - 力扣&#xff08;Leetcode&#xff09; 这道题目不难理解&#xff0c;就是查找最长的无重复字符的最长子串&#xff0c; 最后返回最长子串的…

【LeetCode-中等题】367. 有效的完全平方数

文章目录 题目方法一&#xff1a;二分查找 题目 方法一&#xff1a;二分查找 找 1 - num 之间的 mid&#xff0c; 开方是整数 就找得到 mid&#xff0c; 不是整数自然找不到mid class Solution { // 二分查找 &#xff1b;找 1 - num 之间的mid 开方是整数 就找得到 不是…

正确理解党籍和党龄;入党和转正时间

总的来说党籍、党龄、入党时间、转正时间在性质和时间阶段上均有所区别。 党籍&#xff1a;是指党员资格。经支部党员大会讨论&#xff0c;被批准为预备党员之日起&#xff0c;就有了党籍。若被取消预备党员资格、劝退除名、自行脱党、开除党籍的&#xff0c;就失去了党籍。 …