problem:
There is a total of n courses you have to take, labeled from 0
to n - 1
.
Some courses May has prerequisites, for example to take course 0 you have to first take course 1, which is expressed as a Pair[0,1]
Given the total number of courses and a list of prerequisite pairs, are it possible for your to finish all courses?
For example:
2, [[1,0]]
There is a total of 2 courses to take. To take course 1 should has finished course 0. So it is possible.
2, [[1,0],[0,1]]
There is a total of 2 courses to take. To take course 1 should has finished course 0, and to take course 0 you should also has finished course 1. So it is impossible.
Note:
The input prerequisites is a graph represented by a list of edges, not adjacency matrices. Read more on how a graph is represented.
Analysis:
reference:http://www.programcreek.com/2014/05/leetcode-course-schedule-java/The idea behind ThisProblem is isn't hard, we can treat it as a graph. The problem is to detectifThere is a circle exist. Since the degrees of a node ' s out/in edges could is greatly different, We should consider clear all case.Initial wrong Idea:take advantage of the Queue, we use BFS method to solve Thisproblem through following Pattern:step1: Scan The prerequisites matrix, to identify out of the courses that does does have prerequisites. and add them into Queue.step2: Pop A course out, and unlock all courses based on it as prerequisite, and add all of the them into queue. Step3:when the queue is empty, check the count of poped courses. To decideifAll courses could is studied through certain order. Solution: Public BooleanCanfinish (intNumcourses,int[] Prerequisites) { if(Prerequisites = =NULL) Throw NewIllegalArgumentException ("Invalid Prerequisites Matrix"); intm =prerequisites.length; Boolean[] used =New Boolean[M]; intCount = 0; if(numcourses = = 0 | | m = = 0) return true; Queue<Integer> queue =NewLinkedlist<integer> (); for(inti = 0; I < m; i++) { BooleanNo_pre =true; for(intj = 0; J < M; J + +) {No_pre= No_pre && (prerequisites[i][j] = = 0); } if(no_pre) {queue.offer (i); } } if(queue.size () = = 0)return false; while(!Queue.isempty ()) { intCur =Queue.poll (); Used[cur]=true; Count++; Unlockcourse (Prerequisites, queue, cur, used); } returnCount = =numcourses; } Public voidUnlockcourse (int[] Prerequisites, queue<integer> Queue,intCurBoolean[] used) { intm =prerequisites.length; for(inti = 0; I < m; i++) { //search through BFS must tag the visited element if(Prerequisites[i][cur] = = 1 && used[i] = =false) Queue.offer (i); }} The above solution is wrong forfollowing reasons:1. The graph is represented in edges rather than adjacency matrix.2. A course may has more than one prerequisites!!! You can ' t unlock all courses for a unlocked course. while(!Queue.isempty ()) { intCur =Queue.poll (); Used[cur]=true; Count++; Unlockcourse (Prerequisites, queue, cur, used);} A fix:the above actually has laid a very good foundation forus to fix. The same idea:use a queue forRecording unlocked courses, when a course poped out from the queue, we increase the count of unlocked course. Besides the queue, we also take advantage of a counter array, which records the left prerequisites fora course. Only if the prerequisites count of a course equal to0, we treat it as an unlocked course and add it into the queue. Step1:count The Prerequisites forEach course.int[] Pre_counter =New int[numcourses];intLen =prerequisites.length; for(inti = 0; i < Len; i++) {pre_counter[prerequisites[i][0]]++;} Step2: Put courses that has no prerequisites into the queue. for(inti = 0; i < numcourses; i++) { if(Pre_counter[i] = = 0) Queue.offer (i);} Step3: Unlock courses through unlocked courses. while(!Queue.isempty ()) { intCur =Queue.poll (); Count++; for(inti = 0; i < Len; i++) { //Note the logic here, must [i][1] = = cur, guarantee repeately add in to queue if(Prerequisites[i][1] = =cur) {pre_counter[prerequisites[i][0]]--; if(Pre_counter[prerequisites[i][0]] = = 0) Queue.offer (prerequisites[i][0]); }}}}logic pitfall:i has made following Logic errors, which result in Infinite loop. if(Prerequisites[i][1] = =cur) {pre_counter[prerequisites[i][0]]--;}if(Pre_counter[prerequisites[i][0]] = = 0) {Queue.offer (prerequisites[i][0]);} The most common mistakes on using BFS is to revisit node and add it into the queue again. The mistake I has made at here is a good example. for(inti = 0; i < Len; i++) { ...} This would cause us to revisit pre_counter[prerequisites[i][0]] time and time, and keep on add prerequisites[i][0] to our queue. Thus we usually use a visited arrays to indicate, a course has alredy been unlocked and visisted. But for ThisProblem, we can DoIt's in a and simple . Fix Method: for(inti = 0; i < Len; i++) { if(Prerequisites[i][1] = =cur) {pre_counter[prerequisites[i][0]]--; if(Pre_counter[prerequisites[i][0]] = = 0) Queue.offer (prerequisites[i][0]); }}why It works?First , let us assume the same cur would only be poped once before enter the loop. for(inti = 0; i < numcourses; i++) { if(Pre_counter[i] = = 0) Queue.offer (i);} only for"prerequisites[i][1] = = cur"and it just solved a unlock courses (we can say its the last prerequisites course). We add the course into queue.if(Pre_counter[prerequisites[i][0]] = = 0) Queue.offer (prerequisites[i][0]); Which means, only when a course is just unlocked, we add it into the queue. No other times of adding a element into the queue. Note:the cur would only is poped out, since we add it only once. Another fix method. Use a visited array.Boolean[] visited =New Boolean[numcourses]; while(!Queue.isempty ()) { intCur =Queue.poll (); Visited[cur]=true; Count++; for(inti = 0; i < Len; i++) { //Note the logic here, must [i][1] = = cur, guarantee repeately add in to queue if(Prerequisites[i][1] = =cur) pre_counter[prerequisites[i][0]]--; if(pre_counter[prerequisites[i][0] [= 0 && visited[prerequisites[i][0]] = =false) Queue.offer (prerequisites[i][0]); }}even though This Thiswould solve Infinte loop problem, but it still could exceed time if the size of courses is large. Then reason are that:we keep on visit on all"Pre_counter[prerequisites[i][0]]"no matterif(Prerequisites[i][1] = =cur) This method is rude and wrong, we shouldTryTo avoid uncessary check.if(Prerequisites[i][1] = =cur) {pre_counter[prerequisites[i][0]]--; if(pre_counter[prerequisites[i][0] [= 0 && visited[prerequisites[i][0]] = =false) Queue.offer (prerequisites[i][0]);}
Solution:
Public classSolution { Public BooleanCanfinish (intNumcourses,int[] Prerequisites) { if(Prerequisites = =NULL) Throw NewIllegalArgumentException ("The prerequisites matrix is not valid"); intLen =prerequisites.length; Boolean[] visited =New Boolean[numcourses]; if(numcourses = = 0 | | len = 0) return true; int[] Pre_counter =New int[numcourses]; intCount = 0; Queue<Integer> queue =NewLinkedlist<integer> (); for(inti = 0; i < Len; i++) {pre_counter[prerequisites[i][0]]++; } for(inti = 0; i < numcourses; i++) { if(Pre_counter[i] = = 0) {queue.offer (i); } } while(!Queue.isempty ()) { intCur =Queue.poll (); Visited[cur]=true; Count++; for(inti = 0; i < Len; i++) { //Note the logic here, must [i][1] = = cur, guarantee repeately add in to queue if(Prerequisites[i][1] = =cur) {pre_counter[prerequisites[i][0]]--; if(pre_counter[prerequisites[i][0] [= 0 && visited[prerequisites[i][0]] = =false) Queue.offer (prerequisites[i][0]); } } } returnCount = =numcourses; }}
[leetcode#207] Course Schedule