题目
26年8月4日(少部分自解)
func findOrder(numCourses int, prerequisites [][]int) []int {
nodein:=make([]int,numCourses) //入度表
graph:=make([][]int,numCourses) //邻接表
res:=make([]int,0,numCourses)//注意
for i:=0;i<len(prerequisites);i++{
next,pre:=prerequisites[i][0],prerequisites[i][1]
nodein[next]++
graph[pre]=append(graph[pre],next)
}
visited:=make([]bool,numCourses)
queue:=[]int{}
for i:=range nodein{
if nodein[i]==0{
queue=append(queue,i)
visited[i]=true
res=append(res,i)
//多入度0初始化没考虑
}
}
for len(queue)>0{
cur:=queue[0]
queue=queue[1:]
for _,v:=range graph[cur]{
if visited[v]==true{
continue
}
//判断顺序错
nodein[v]--
if nodein[v]==0{
queue=append(queue,v)
res=append(res,v)
visited[v]=true
}
}
}
if len(res)==numCourses{
return res
}else{
return []int{}
}
}
思路
拓扑排序(BFS),使用于比如有先置条件的有向图。比如选了课程0,才能选课程1,选了课程2,才能选课程1。等等
这样形成依赖关系后,会形成如图的关系。这样我们能发现规律,最开始要选入度为0的节点,也就是没有先置条件的。比如这里选0,而选了0后,对于1和2他们的先置条件满足了可以选了,对应图中我们此时把0去掉,让节点1和2的入度-1变为0。这样就比较好想代码逻辑,是类似队列BFS的
对于删除节点,我们就用visited数组标记模拟
这样我们在标记visit,同时能避免后续的节点选择到之前已经加入队列的入度为0的节点。
然后我们删除后,还有把这个入度节点指向的next节点的入度-1,所以我们一开始不仅要记录入度,如下
nodein:=make([]int,numCourses)//入度表
还有记录指向关系,graph邻接表,能寻找到next节点。
graph:=make([][]int,numCourses) //邻接表
不过这道题还有坑,就是可能会出现有环的情况,都出现环了说明之前选过肯定不能选,但是并不是有环就一定不能选完所有节点。
if visited[v]==true{ continue }
这里visited数组再次发挥作用,先判断之前有没有遍历过,如果遍历过说明这里出现后环了,那么就跳过。