因为6.824要用go,所以打算用go刷一阵子题,熟悉一下语言,过阵子做的时候好上手
另一方面也是好久没有认真刷题了 熟练度噌噌的掉
你这个学期必须选修 numCourse 门课程,记为 0 到 numCourse-1 。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:[0,1]
给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?
示例 1:
输入: 2, [[1,0]]
输出: true
解释: 总共有 2 门课程。学习课程 1 之前,你需要完成课程 0。所以这是可能的。
示例 2:输入: 2, [[1,0],[0,1]]
输出: false
解释: 总共有 2 门课程。学习课程 1 之前,你需要先完成课程 0;并且学习课程 0 之前,你还应先完成课程 1。这是不可能的。
提示:
输入的先决条件是由 边缘列表 表示的图形,而不是 邻接矩阵 。详情请参见图的表示法。
你可以假定输入的先决条件中没有重复的边。
1 <= numCourses <= 10^5
在有向图中,优先级限制下的调度问题等价于拓扑排序问题,所以本题主要是运用拓扑排序算法
本题要问的是是否可行,通过判断有无环 如果没环,拓扑排序能否排到所有的元素(突然想到,DAG一定是可以拓扑排序的吗?)
有两种做法,bfs,dfs
bfs:
const (
src = 1
dst = 0
)
// 原理是判断是多源的搜索能否遍历整个图,当然首先要确保有一个源(不是环)
// 使用map 作为邻接表
// 问题在于:每次mark的时候 要保证他没有其他入度了 如果是单纯的搜索意味着要不断的修改count
func canFinish(numCourses int, prerequisites [][]int) bool {
out := make(map[int][]int)
in := make(map[int][]int)
for i := 0; i < len(prerequisites); i++ {
out[prerequisites[i][src]] = append(out[prerequisites[i][src]], prerequisites[i][dst])
in[prerequisites[i][dst]] = append(in[prerequisites[i][dst]], prerequisites[i][src])
}
var source []int
inCount := make([]int, numCourses)
for i := 0; i < numCourses; i++ {
if len(in[i]) == 0 {
source = append(source, i)
}
inCount[i] = len(in[i])
}
if len(source) == 0 {
return false
}
marked := make([]bool, numCourses)
for {
if len(source) == 0 {
break
}
s := source[0]
source = source[1:]
marked[s] = true
for _, v := range out[s] {
inCount[v]--
}
for _, v := range out[s] {
if marked[v] == false && inCount[v] == 0 {
source = append(source, v)
}
}
}
for _, v := range marked {
if v == false {
return false
}
}
return true
}
dfs:
这里有一个结论:拓扑排序就是reverse dfs
const (
src = 1
dst = 0
)
func dfs(out map[int][]int, marked []bool, start int, rs *[]int, onStack []bool, hasCycle *bool) {
if marked[start] == true {
return
}
marked[start] = true
onStack[start] = true
for _, v := range out[start] {
if *hasCycle == true {
return
}
if onStack[v] == true {
*hasCycle = true
}
dfs(out, marked, v, rs, onStack, hasCycle)
}
onStack[start] = false
*rs = append(*rs, start)
}
// 原理是判断是多源的搜索能否遍历整个图,当然首先要确保有一个源(不是环)
// 使用map 作为邻接表
// 问题在于:每次mark的时候 要保证他没有其他入度了 如果是单纯的搜索意味着要不断的修改count
func canFinish(numCourses int, prerequisites [][]int) bool {
out := make(map[int][]int)
in := make(map[int][]int)
for i := 0; i < len(prerequisites); i++ {
out[prerequisites[i][src]] = append(out[prerequisites[i][src]], prerequisites[i][dst])
in[prerequisites[i][dst]] = append(in[prerequisites[i][dst]], prerequisites[i][src])
}
var source []int
inCount := make([]int, numCourses)
for i := 0; i < numCourses; i++ {
if len(in[i]) == 0 {
source = append(source, i)
}
inCount[i] = len(in[i])
}
if len(source) == 0 {
return false
}
marked := make([]bool, numCourses)
var rs []int
onStack := make([]bool, numCourses)
hasCycle := false
for _, s := range source {
dfs(out, marked, s, &rs, onStack, &hasCycle)
}
if hasCycle == true {
return false
}
return len(rs) == numCourses
}
这两种做法都是算法4里提到过的,正文讲到的是reverse dfs,习题里提到的是bfs
本文通过Go语言探讨LeetCode 207题,研究如何判断在给定课程的先决条件下是否能完成所有课程的学习。文章介绍拓扑排序的概念,并提供了两种解决方法:深度优先搜索(DFS)和广度优先搜索(BFS)。通过拓扑排序判断图中是否存在环,并以此确定课程选修的可行性。

被折叠的 条评论
为什么被折叠?



