Topological sorting for Directed Acyclic Graph (DAG) is a linear ordering of vertices such that for every directed edge u v, vertex u comes before v in the ordering.1
Note: Topological Sorting for a graph is not possible if the graph is not a DAG. (i.e. If there is a loop/cycle in the Graph)
Below is the implementation of the above approach:
fromcollectionsimportdefaultdict# DAG - topological sortingclassSolution:deffindOrder(self,numCourses:int,prerequisites:List[List[int]])->List[int]:ifnotprerequisites:returnlist(range(numCourses))adj_lit=defaultdict(list)forc0,c1inprerequisites:adj_lit[c0].append(c1)deftraverse(c0):'''check a vertix's prerequisite'''visited[c0]=Trueforcsinadj_lit[c0]:ifnotvisited[cs]:traverse(cs)# DFSstack.append(c0)visited=[False]*numCoursesstack=[]adj_keys=list(adj_lit.keys())# to handle defaultdict's size changed during iteration in line-12forc0inadj_keys:ifnotvisited[c0]:traverse(c0)returnstack# Failed at task like:# n = 2# prerequisites = [[0,1],[1,0]]
But I quickly realized I’ve missed to handle the loop. Then I tried again.
###### still failed at n=2, pre=[[0,1],[1,0]] ###### classSolution:deffindOrder(self,numCourses:int,prerequisites:List[List[int]])->List[int]:adj_list=[[]for_inrange(numCourses)]forc0,c1inprerequisites:adj_list[c0].append(c1)defDFS(c0,master):visited[c0]=Trueforc1inadj_list[c0]:# detect loop (cycle)ifadj_list[c1]==master:acycle[0]=Falseifnotvisited[c1]:DFS(c1,master)output.append(c0)visited=[False]*numCoursesoutput=[]acycle=[True]forc0inrange(numCourses):ifacycle[0]==False:return[]ifnotvisited[c0]:# independent courseifadj_list[c0]==[]:visited[c0]=Trueoutput.append(c0)else:DFS(c0,c0)returnoutput###### still failed at n=2, pre=[[0,1],[1,0]] ######
Still missing…
Then I adopted the solution from archit91 with BFS approach. It’s nicely structured and well-run.
There are a total of numCourses courses you have to take, labeled from 0 to numCourses - 1. You are given an array prerequisites where prerequisites[i] = [ai, bi] indicates that you must take course bi first if you want to take course ai.
For example, the pair [0, 1], indicates that to take course 0 you have to first take course 1.
Return true if you can finish all courses. Otherwise, return false.
Example 1:
Input: numCourses = 2, prerequisites = [[1,0]]
Output: true
Explanation: There are a total of 2 courses to take.
To take course 1 you should have finished course 0. So it is possible.
# if there is a loop, it won't be possible to finish all coursesfromcollectionsimportdefaultdict,dequeclassSolution:defcanFinish(self,numCourses:int,prerequisites:List[List[int]])->bool:graph=defaultdict(list)pre_cs_list=[0]*numCoursesfornext_c,pre_cinprerequisites:graph[pre_c].append(next_c)pre_cs_list[next_c]+=1q=deque()# check independent courcesforiinrange(numCourses):ifpre_cs_list[i]==0:q.append(i)ans=[]whileq:curr=q.popleft()ans.append(curr)fornext_cingraph[curr]:pre_cs_list[next_c]-=1ifpre_cs_list[next_c]==0:q.append(next_c)returnlen(ans)==numCourses