-
Notifications
You must be signed in to change notification settings - Fork 639
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
leetcode207:课程表问题 #66
Labels
Comments
/**
* @param {number} numCourses
* @param {number[][]} prerequisites
* @return {boolean}
*/
var canFinish = function(numCourses, prerequisites) {
const graph={};
const degree=new Array(numCourses).fill(0);
// 采用邻接表来保存课程的依赖关系,并且记录被依赖课程的先导次数
for(const it of prerequisites){
if(graph[it[0]]===undefined) graph[it[0]]=[it[1]]
else graph[it[0]].push(it[1])
degree[it[1]]++;
}
//degree[i]为0,表示该课程不属于任何课程的先导课
// 则需要将这些课程编号入栈
const stack=[];
for(let i=0;i<numCourses;i++){
if(degree[i]===0) stack.push(i)
}
let cnt=0;
while(stack.length){
const c=stack.pop();
cnt++;
for(const pre of (graph[c]||[c])){
// 注意下面degree[pre]可能为负数,但是不影响结果
degree[pre]--;
if(degree[pre]===0) {
stack.push(pre)
}
}
}
return cnt===numCourses
}; |
这是一道经典的拓扑排序问题,所谓拓扑排序,举个例子: 比如吃自助火锅,有一套约定俗成的流程,首先先打开包装,然后放入粉、佐料、菜,然后在加水,最后盖上盖子;这是有一套先后顺序的,你不可能没打开包装就放佐料,也可以说这是有一套依赖关系的,盖盖子依赖加水,加水依赖放入粉、佐料、菜,继而依赖打开包装 这种关系通常使用有向图来表示,如果这套流程能够成功的帮助你最后吃到火锅(无环),那这种依赖顺序就是拓扑排序,即拓扑排序是针对有向无环图的 解法:广度优先遍历例如: 输入: 5, [[4,2],[4,3],[2,0],[2,1]] 所以我们可以使用 邻接表 来表示有向图中各个节点的依赖关系,同时维护一个入度表,则入度表中入度为 那么这题就很简单了:
let canFinish = function(numCourses, prerequisites) {
// 如果没有先决条件,即所有的课程均没有依赖关系
// 直接返回 true
if (prerequisites.length === 0) {
return true
}
// 维护入度表
let inDegree = new Array(numCourses).fill(0)
// 维护临接表
let adj = new Map()
for (let e of prerequisites) {
inDegree[e[0]]++
if(!adj.has(e[1])) adj.set(e[1], [])
let vEdge = adj.get(e[1])
vEdge.push(e[0])
}
let queue = []
// 首先加入入度为 0 的结点
for (let i = 0; i < numCourses; i++) {
if (inDegree[i] === 0) {
queue.push(i)
}
}
while (queue.length > 0) {
// 从队首移除
var v = queue.shift()
// 出队一门课程
numCourses--
if(!adj.has(v)) continue
// 遍历当前出队结点的所有临接结点
for(let w of adj.get(v)) {
inDegree[w]--
if (inDegree[w] === 0) {
queue.push(w)
}
}
}
return numCourses === 0
} 复杂度分析:
|
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
你这个学期必须选修
numCourse
门课程,记为0
到numCourse-1
。在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们:
[0,1]
给定课程总量以及它们的先决条件,请你判断是否可能完成所有课程的学习?
示例 1:
示例 2:
提示:
1 <= numCourses <= 10^5
附赠leetcode地址:leetcode
The text was updated successfully, but these errors were encountered: