做LC新出的题:先行课课程表,看到了Topological Sorting.
回想起去年有次在群里跟同学讨论一道类似的题。当时还不知道Topological,就自顾自地做了一番,后来别人来一个提一次,都说用Topological。连解释都没有。我就郁闷了。后来也没看。今天总结性一次搞定。
鱼C的帖子 精简
从AOV网中选择一个没有前趋的顶点(该顶点的入度为0)并且输出它;
从网中删去该顶点,并且删去从该顶点发出的全部有向边;
重复上述两步,直到剩余网中不再存在没有前趋的顶点为止。
算法时间复杂度:
对一个具有n个顶点,e条边的网来说,初始建立入度为零的顶点栈,要检查所有顶点一次,执行时间为O(n)。
排序中,若AOV网无回路,则每个顶点入、出栈各一次,每个表结点被检查一次,因而执行时间是 O(n+e)。
所以,整个算法的时间复杂度是 O(n+e)。
CSDN拓扑排序的原理及其实现 (详细)
有向图的拓扑排序
Coursera 课程讲解
最后是LC上的代码:
public int[] findOrder(int numCourses, int[][] prerequisites){
--// nextVertex中的每个entry,int指课程,set指此课程的所有先行课
--Map
--// preVertex[i] 记录课程“i”是先行课的次数
--int[] preVertex = new int[numCourses];
--// 扫描所有先行课限制
--for(int i = 0; i < prerequisites.length; i++){
----if(!nextVertex.containsKey(prerequisites[i][0]))
------nextVertex.put(prerequisites[i][0], new HashSet<>());
----// boolean add(E e), 如果e已经存在,Set的add方法返回false。
----// 每门课只记录其第一个先行课!从第二个起add返回false,避免dup。
----if (nextVertex.get(prerequisites[i][0]).add(prerequisites[i][1]))
------preVertex[prerequisites[i][1]]++;
--}
--// BFS Queue,
--Deque
--for(int i = 0; i < preVertex.length; i++)
----if(preVertex[i] == 0) queue.offerLast(i); // 记录所有没被当作先行课的课程
--//把不是先行课的课程依次倒着插入。
--int[] res = new int[numCourses]; // 最终输出
--int index = res.length - 1; //倒着来
--while(!queue.isEmpty()){
----int key = queue.pollFirst();
----res[index--] == key;
----// 更新此课的所有后行课
----if(nextVertex.containsKey(key)){
----for(int i:nextVertex.get(key)) // 便利set
------if(--preVertex[i] == 0) // 如果此后行课没有别的先行课了
--------queue.offerLast(i); //存入queue
----}
----numCourses; // 更新所剩课程数
--}
--// 如果课程都被包了,返回结果,不然返回新array
--return numCourses == 0 ? res
}