目录
1. 课程表 Course Schedule I 🌟🌟
2. 课程表 Course Schedule II 🌟🌟
🌟 每日一练刷题专栏 🌟
Rust每日一练 专栏
Golang每日一练 专栏
Python每日一练 专栏
C/C++每日一练 专栏
Java每日一练 专栏
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]
🌟 每日一练刷题专栏 🌟
✨ 持续,努力奋斗做强刷题搬运工!
👍 点赞,你的认可是我坚持的动力!
🌟 收藏,你的青睐是我努力的方向!
✎ 评论,你的意见是我进步的财富!
☸ 主页:https://hannyang.blog.csdn.net/
Rust每日一练 专栏(2023.5.16~)更新中... | |
Golang每日一练 专栏(2023.3.11~)更新中... | |
Python每日一练 专栏(2023.2.18~2023.5.18)暂停更 | |
C/C++每日一练 专栏(2023.2.18~2023.5.18)暂停更 | |
Java每日一练 专栏(2023.3.11~2023.5.18)暂停更 |