1. 课程表 Course Schedule I
你这个学期必须选修 numCourses
门课程,记为 0
到 numCourses - 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 <= 10^5
0 <= prerequisites.length <= 5000
prerequisites[i].length == 2
0 <= ai, bi < numCourses
prerequisites[i] 中的所有课程对 互不相同
代码1: DFS
package main import "fmt" func canFinish(numCourses int, prerequisites [][]int) bool { // 构建邻接表 graph := make([][]int, numCourses) for _, p := range prerequisites { graph[p[1]] = append(graph[p[1]], p[0]) } // DFS 遍历找环 visited := make([]bool, numCourses) for i := 0; i < numCourses; i++ { if !dfs(i, graph, visited) { return false } } return true } func dfs(node int, graph [][]int, visited []bool) bool { if visited[node] { return false } visited[node] = true for _, n := range graph[node] { if !dfs(n, graph, visited) { return false } } visited[node] = false return true } func main() { numCourses := 2 prerequisites := [][]int{{1, 0}} fmt.Println(canFinish(numCourses, prerequisites)) prerequisites = [][]int{{1, 0}, {0, 1}} fmt.Println(canFinish(numCourses, prerequisites)) }
代码2: BFS 拓扑排序
package main import "fmt" func canFinish(numCourses int, prerequisites [][]int) bool { // 建图,统计入度 graph := make([][]int, numCourses) inDegree := make([]int, numCourses) for _, p := range prerequisites { graph[p[1]] = append(graph[p[1]], p[0]) inDegree[p[0]]++ } // 将入度为 0 的结点加入队列中 queue := make([]int, 0) for i := 0; i < numCourses; i++ { if inDegree[i] == 0 { queue = append(queue, i) } } // BFS 遍历图 for len(queue) > 0 { node := queue[0] queue = queue[1:] numCourses-- for _, n := range graph[node] { inDegree[n]-- if inDegree[n] == 0 { queue = append(queue, n) } } } return numCourses == 0 } func main() { numCourses := 2 prerequisites := [][]int{{1, 0}} fmt.Println(canFinish(numCourses, prerequisites)) prerequisites = [][]int{{1, 0}, {0, 1}} fmt.Println(canFinish(numCourses, prerequisites)) }
输出:
true
false
2. 课程表 Course Schedule II
现在你总共有 numCourses 门课需要选,记为 0 到 numCourses - 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]
提示:
1 <= numCourses <= 2000
0 <= prerequisites.length <= numCourses * (numCourses - 1)
prerequisites[i].length == 2
0 <= ai, bi < numCourses
ai != bi
所有[ai, bi] 互不相同
代码1: DFS
package main import "fmt" func findOrder(numCourses int, prerequisites [][]int) []int { // 构建邻接表和标记数组 graph := make([][]int, numCourses) marks := make([]int, numCourses) for _, p := range prerequisites { graph[p[1]] = append(graph[p[1]], p[0]) } // DFS 拓扑排序 order := make([]int, 0) for i := 0; i < numCourses; i++ { if marks[i] == 0 { if !dfs(graph, marks, i, &order) { return []int{} } } } // 倒序输出拓扑排序 for i, j := 0, len(order)-1; i < j; i, j = i+1, j-1 { order[i], order[j] = order[j], order[i] } return order } func dfs(graph [][]int, marks []int, node int, order *[]int) bool { marks[node] = 1 for _, n := range graph[node] { if marks[n] == 1 { return false // 发现环 } if marks[n] == 0 { if !dfs(graph, marks, n, order) { return false // 发现环 } } } marks[node] = 2 *order = append(*order, node) return true } func ArrayToString(arr []int) string { res := "[" for i := 0; i < len(arr); i++ { res += fmt.Sprint(arr[i]) //对[]int数组可以用strconv.Itoa(arr[i]) if i != len(arr)-1 { res += "," } } return res + "]" } func main() { numCourses := 2 prerequisites := [][]int{{1, 0}} res := findOrder(numCourses, prerequisites) fmt.Println(ArrayToString(res)) numCourses = 4 prerequisites = [][]int{{1, 0}, {2, 0}, {3, 1}, {3, 2}} res = findOrder(numCourses, prerequisites) fmt.Println(ArrayToString(res)) }
输出:
[0,1]
[0,2,1,3]
代码2: BFS 拓扑排序
package main import "fmt" func findOrder(numCourses int, prerequisites [][]int) []int { // 构建邻接表和入度数组 graph := make([][]int, numCourses) inDegree := make([]int, numCourses) for _, p := range prerequisites { graph[p[1]] = append(graph[p[1]], p[0]) inDegree[p[0]]++ } // 入度为 0 的结点入队列 queue := make([]int, 0) for i := 0; i < numCourses; i++ { if inDegree[i] == 0 { queue = append(queue, i) } } order := make([]int, 0) // 拓扑排序 for len(queue) > 0 { node := queue[0] queue = queue[1:] order = append(order, node) numCourses-- for _, n := range graph[node] { inDegree[n]-- if inDegree[n] == 0 { queue = append(queue, n) } } } if numCourses == 0 { return order } else { return []int{} } } func ArrayToString(arr []int) string { res := "[" for i := 0; i < len(arr); i++ { res += fmt.Sprint(arr[i]) //对[]int数组可以用strconv.Itoa(arr[i]) if i != len(arr)-1 { res += "," } } return res + "]" } func main() { numCourses := 2 prerequisites := [][]int{{1, 0}} res := findOrder(numCourses, prerequisites) fmt.Println(ArrayToString(res)) numCourses = 4 prerequisites = [][]int{{1, 0}, {2, 0}, {3, 1}, {3, 2}} res = findOrder(numCourses, prerequisites) fmt.Println(ArrayToString(res)) }
输出:
[0,1]
[0,1,2,3]