题目链接: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
}