题目描述:
现在你总共有 n 门课需要选,记为 0 到 n-1。
在选修某些课程之前需要一些先修课程。 例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示他们: [0,1]
给定课程总量以及它们的先决条件,返回你为了学完所有课程所安排的学习顺序。
可能会有多个正确的顺序,你只要返回一种就可以了。如果不可能完成所有课程,返回一个空数组。
今日学习:
1.图的表示法
2.DFS和BFS
3.复习Set、splice
4.数组的交、并、补集
题解1:(又是我失败的题解Orz)
var findOrder = function(numCourses, prerequisites) {
//我自己的想法,果然又失败了Orz
if(prerequisites.length == 0){return [];}
var ord = [];
function find(numCourses, prerequisites){
if(prerequisites.length == 1){
ord.push(prerequisites[0][1]);
ord.push(prerequisites[0][0]);
if(ord.length == numCourses){
return ord;
}else{
return [];
}
}else if(prerequisites.length > 1){
var pre = new Set();
var later = new Set();
//pre为先序课程,later为后序课程
for(var i = 0; i < prerequisites.length; i++){
pre[i] = prerequisites[i][1];
later[i] = prerequisites[i][0];
}
//后序课程与先序课程集合不重叠时结束
var preArr = [...pre], laterArr = [...later];
let intersection = preArr.filter(function (val) { return laterArr.indexOf(val) > -1 });
if(intersection === []){
for(var i = 0; i < pre.size; i++){
ord.push(pre[i])
}
for(var i = 0; i < later.size; i++){
ord.push(later[i])
}
return ord;
}
//只保留最根源的先序课程
for(var i = 0; i < later.size; i++){
if(later.has(pre[i])){
pre.delete(pre[i])
}
}
//将最根源的先序课程推入结果数组中
ord.push(pre[0]);
//将含有先序课程的课程对从先决条件中删除
for(var i = 0; i < prerequisites.length; i++){
var toDel = prerequisites[i];
if(prerequisites[i].indexOf(pre[0]) != -1){
var del = prerequisites.indexOf(toDel);
prerequisites.splice(del, 1);
}
}
//开始新一轮查找
find(numCourses, prerequisites);
}
}
var ordRes = find(numCourses, prerequisites);
return ordRes;
};
我的想法是每一次都把先序课程找出来,然后从prerequisites中删除该课程对再开始新一轮查找,但是局限性太大,很多情况不一定包含的进去
题解2:参考
var findOrder = (numCourses, prerequisites) => {
let inDegree = new Array(numCourses).fill(0) // 初始化入度数组
let graph = {} // 哈希表
for (let i = 0; i < prerequisites.length; i++) {
inDegree[prerequisites[i][0]]++ // 构建入度数组
if (graph[prerequisites[i][1]]) { // 构建哈希表
graph[prerequisites[i][1]].push(prerequisites[i][0])
} else {
let list = []
list.push(prerequisites[i][0])
graph[prerequisites[i][1]] = list
}
}
let res = [] // 结果数组
let queue = [] // 存放 入度为0的课
for (let i = 0; i < numCourses; i++) { // 起初推入所有入度为0的课
if (inDegree[i] === 0) queue.push(i)
}
while (queue.length) { // 没有了入度为0的课,没课可选,结束循环
let cur = queue.shift() // 出栈,代表选这门课
res.push(cur) // 推入结果数组
let toEnQueue = graph[cur] // 查看哈希表,获取对应的后续课程
if (toEnQueue && toEnQueue.length) { // 确保有后续课程
for (let i = 0; i < toEnQueue.length; i++) { // 遍历后续课程
inDegree[toEnQueue[i]]-- // 将后续课程的入度 -1
if (inDegree[toEnQueue[i]] == 0) { // 一旦减到0,让该课入列
queue.push(toEnQueue[i])
}
}
}
}
return res.length === numCourses ? res : [] // 选齐了就返回res,否则返回[]
};