# 207 Course Schedule
給一正整數表示課堂總數、和二維整數矩陣表示某課需要先修另一門課,e.g. [1,2] 表示course 1 需要先修course2。
問根據提供的課堂資料,是否有可能修完所有的課呢?
2, [[1,0] => true
2, [[1,0],[0,1]] => false
Idea 一開始想用2d boolean array表示課堂之間的關係,size為numCourses * numCourses,若(i,j)位置為true,表示課堂i需要先修課堂j。
後來又想到每個課堂可以表示為node,就可以畫成graph,上面的兩個例子分別可以畫成這樣的圖
0 -> 1
0 -> 1
<-
此時就發現當有cycle時,就表示不可能修完所有的課。
再來就是要決定怎麼存課程之間的相依關係,最後決定用map,map裡的key為course number,value是一個List
Pseudocode
visit all entries in prerequisites and create a map
visit all entries in the map
queue of prerequesites
while(queue is not empty)
if prereq is in map
if prereq's value is the same as current entry
return false
put prereq's value in to queue
return true
Code
class Solution {
public boolean canFinish(int numCourses, int[][] prerequisites) {
Map<Integer, List<Integer>> map = new HashMap<>();
//create map
for(int i=0; i<prerequisites.length; i++){
int key = prerequisites[i][0];
if(map.get(key) != null){
List<Integer> list = map.get(key);
list.add(prerequisites[i][1]);
map.put(key, list);
}else{
map.put(key, new ArrayList<>(Arrays.asList(prerequisites[i][1])));
}
}
//visit all entries in map
for(Map.Entry<Integer, List<Integer>> entry: map.entrySet()) {
Queue<Integer> prereq = new LinkedList<>();
for(int i: entry.getValue()){
prereq.add(i);
}
while(!prereq.isEmpty()){
int cur = prereq.remove();
if(map.get(cur) != null){
List<Integer> list = map.get(cur);
for(int j : list){
if(j == entry.getKey())
return false;
else
prereq.add(j);
}
}
}
}
return true;
}
}
這個解法可以過27/42 test cases,最後會TLE。 Time Complexity Analysis: prerequisites array can be n^2. total number of map entry should be n. each list can be as large as n-1. in the while loop, the queue can be as big as n^2. Thus, the second loop is bound by O(n^3)
Optimize 用我最一開始想的2d array紀錄,並且加上一個visited array,標記是否重複拜訪某個點,如此一來可以快速找到cycle,
class Solution {
/*
Pseudo Code: {2, [0,1]}
bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
Construct graph
Construct a visited array
Go through each node
DFS to search if there's cyle
if there's cyle, return false
return true
}
bool dfs(int courseNo, vector<int> &visitState)
{
if visitState is VISITING, return true; //cycle
if visitState is VISITED, return false; //no cycle
marked as VISITING
for all neighbors of courseNo
dfs(neighborNo, visitState)
marked as VISITED
return false;
}
*/
public boolean canFinish(int numCourses, int[][] prerequisites) {
int[][] graph = new int[numCourses][numCourses];
int[] visited = new int[numCourses];//0 - not visit yet, 1 - visiting, 2 - visited
for(int i=0; i<prerequisites.length; i++){
int courseNum = prerequisites[i][0];
int prereq = prerequisites[i][1];
graph[courseNum][prereq] = 1; // 1 : indicate courseNum requires prereq
}
for(int i=0; i<prerequisites.length; i++){
int courseNum = prerequisites[i][0];
if(dfs(courseNum, visited, graph))//return true if there's a cycle
return false;
}
return true;
}
private boolean dfs(int courseNum, int[] visited, int[][] graph){
if(visited[courseNum] == 1)//cycle
return true;
if(visited[courseNum] == 2)//no cycle
return false;
visited[courseNum] = 1;
for(int i = 0; i<visited.length; i++){
if(graph[courseNum][i] == 1){
if(dfs(i, visited, graph)) return true;
}
}
visited[courseNum] = 2;
return false;
}
}