2-28 210.课程表 II
Date:2022-03-06 20:01:10
题目:210.课程表 II(😕)
图
、拓扑排序
、BFS(广度优先搜索)
现在你总共有 n 门课需要选,记为 0 到 n-1。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]
给定课程总量以及它们的先决条件,返回你为了学完所有课程所安排的学习顺序。
可能会有多个正确的顺序,你只要返回一种就可以了。如果不可能完成所有课程,返回一个空数组。
示例
示例1
输入: 2, [[1,0]]
输出: [0,1]
解释: 总共有 2 门课程。要学习课程 1,你需要先完成课程 0。因此,正确的课程顺序为 [0,1] 。
示例2
输入: 4, [[1,0],[2,0],[3,1],[3,2]]
输出: [0,1,2,3] or [0,2,1,3]
解释: 总共有 4 门课程。要学习课程 3,你应该先完成课程 1 和课程 2。并且课程 1 和课程 2 都应该排在课程 0 之后。 因此,一个正确的课程顺序是 [0,1,2,3] 。另一个正确的排序是 [0,2,1,3]
说明
- 输入的先决条件是由边缘列表表示的图形,而不是邻接矩阵。详情请参见图的表示法。
- 你可以假定输入的先决条件中没有重复的边。
前提知识
图、拓扑排序、DFS、BFS(深度、广度优先搜索)
分析
此题虽然根据他人代码,我也做出来了,但过程还是没理解。由于本身对图认识不够,后续还要加强练习
题解
function main() {
const numCourses = 4
const prerequisites = [
[1, 0],
[2, 0],
[3, 1],
[3, 2],
]
console.log('[]:', findOrder(numCourses, prerequisites))
}
main()
function findOrder(numCourses: number, prerequisites: number[][]): number[] {
let res = []
// 计算入度和关系
// 这里的关系是 依赖课程: [课程1,课程2],也就是指课程1和2依赖于依赖课程
const inDeeps = new Array(numCourses).fill(0)
const relationship: {
[key: number]: number[]
} = {}
for (let i = 0; i < prerequisites.length; ++i) {
const value = prerequisites[i][0]
const dep = prerequisites[i][1]
inDeeps[value]++
if (relationship[dep]) {
relationship[dep].push(value)
} else {
relationship[dep] = [value]
}
}
// 生成队列
const queue = []
for (let i = 0; i < inDeeps.length; ++i) {
// 只需要入度为0的,因为这是开始条件,注意queue中放的是课程编号
if (inDeeps[i] == 0) queue.push(i)
}
console.log('[queue]:', queue)
// 开始广度优先搜索
while (queue.length) {
const dep = queue.shift()
res.push(dep)
// 后续的课程
const courses = relationship[dep]
for (let i = 0; courses && i < courses.length; ++i) {
const course = courses[i]
// 向后推进
const depAfter = --inDeeps[course]
if (depAfter == 0) {
queue.push(course)
}
}
}
// 结果的数量,一定与总课程数一致
return res.length == numCourses ? res : []
}
这是根据代码,分析的一次各个变量的状态
4, [[1,0],[2,0],[3,1],[3,2]]
inDeep:
[
0,1,1,2
]
queue:
[
0
]
relationship:
[
'0': [1, 2],
'1': [3],
'2': [3]
]
扩展1:图、拓扑序列
图基础知识
入度:指向改点的边数
扩展2:贪心算法
贪心算法简而言之:每一步最优,则全局最优。