携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情
主要用来循环依赖检测。如,[['A', 'B'], ['B', 'C'], ['C', 'D'], ['B', 'D']] => false,[['A', 'B'], ['B', 'C'], ['C', 'A']] => true
注意:建议先学会BFS再解题
接下来请刷题 lc207 leetcode.cn/problems/co…
题目描述
他会给你学习条件数组,没提及的就是可以自由学,画个图举个例子
n = 6,先决条件表:[[3, 0], [3, 1], [4, 1], [4, 2], [5, 3], [5, 4]]
一眼看就知道是可以学完的,如果学0需要先学5,那就有循环了,就学不了0,学不完了
解题思路
把能学的先学了,比如 0 1 2 ,再把他们指向的箭头去掉
这样 3 4 前面也没箭头了,也能学了,同上操作,最后发现都学完了那就说明没循环。
这样做,需要一个入度表, [ 0, 0, 0, 2, 2, 2 ] 表示课程0需要前置技能0个,用来知道哪些可以学
一个邻接表,记录课程学完可以学的高阶课程,用来学完剪去箭头
{ '0': [ 3 ], '1': [ 3, 4 ], '2': [ 4 ], '3': [ 5 ], '4': [ 5 ] }
然后就可以 学完能学的,减掉箭头,得到新的能学的,一直循环直到没得学了,如果学到的数量和要求的一致,说明没有循环,能完成课程
比如 dnf 红狗 学了开双刀 才能学 大蹦 ,觉醒技能需要先学 大蹦,那么双刀就是0,大蹦1,觉醒2。把双刀学了,大蹦变成0,觉醒变成1。
代码
var canFinish = function(numCourses, prerequisites) {
// 拓扑排序
// 举个例子 6 [[3, 0], [3, 1], [4, 1], [4, 2], [5, 3], [5, 4]]
// inQuery 记录那些课程的前提课程数量 [ 0, 0, 0, 2, 2, 2 ] 课程0需要前置技能0个
// 比如 dnf 红狗 学了开双刀 才能学 大蹦 ,觉醒技能需要先学 大蹦,那么双刀就是0,大蹦1,觉醒2
// map 邻接表,记录课程学完可以学的高阶课程
// { '0': [ 3 ], '1': [ 3, 4 ], '2': [ 4 ], '3': [ 5 ], '4': [ 5 ] } 课程0学完可以学3
let inQuery = new Array(numCourses).fill(0),map = {}
// 遍历条件数组,得到该要的数据
prerequisites.forEach(i=>{
// 可以改一下写法 let [a,b] = i
inQuery[i[0]]++
if(map[i[1]]){
map[i[1]].push(i[0])
}else{
map[i[1]]=[i[0]]
}
})
// 找出低阶技能,不需要前提 [ 0, 1, 2 ]
let query = []
for(let i=0;i<inQuery.length;i++){
if(inQuery[i]==0)query.push(i)
}
console.log(inQuery,map,query)
let count = 0
// 类似BFS,取出不需要前置学习的课程,让他们指向的高阶技能的前置技能数-1,如果变为0那就说明能学了,加进来
// 就是比如你学了双刀,觉醒需要的前置技能数-1,再学个大蹦就能学了
// 再遍历,直到能学的都学了,如果学到的和要学的数量是一样的,那就能完成
while(query.length){
// 拿到能学的,得到 指向的高阶技能数组
let a = map[query.shift()]
count++
if(a?.length){
// 遍历指向的高阶技能数组 , -1
a.forEach(i=>{
inQuery[i]--
if(inQuery[i]==0){
query.push(i)
}
})
}
}
console.log(count)
return count==numCourses
};
这个也类似 210. 课程表 II
参考:
拓扑介绍:mp.weixin.qq.com/s/pCRscwKqQ…
别人的题解:leetcode.cn/problems/co…