207 course schedule

207 course schedule 


// dfs 

class Solution{
  public boolean canFinish(int numCourses, int[][] prerequisites){
    ArrayList<ArrayList<Integer>> graph = new ArrayList<>();
    
    
    // build a adj list 
    for(int i = 0; i < numCourses; i++){
      graph.add(new ArrayList<Integer>());
    }
    
    //  key: class A, value : a list of classes you can take after taking class A 
 
    // need to go thru the input, all the prerequisite information , and store them into the adj list 
    for(int i = 0; i < prerequisites.length; i++){
      int course = prerequisites[i][0];
      int pre = prerequisites[i][1];
      graph.get(pre).add(course);
    }

    
    
    // need to keep track of the visited status 
    int[] visited = new int[numCourses];
    
    // want to make sure we don't skip any nodes/courses (because graph can have more than one single connected component), we emumerate every class. why the order of enumerating doesnt matter? 
    // once we have found a cycle, then we can just report that we found a cycle and exit, no need to emumerate other nodes/courses, one cycle is enough for us not have a right order to finish all the classes. 
    
    // need to try different enumerating orders, to see why it doesn't matter.. (todo)
    // we have this magic func called hasCycle to help us check if the path starting from i is a cycle or not, i'm still not sure how it doesn it exactly. 
    for(int i = 0; i < numCourses; i++){
      if(hasCycle(i, graph, visited)){
        return false;
      }
    }
    return true;
  }
  
  
  // this is where the magic happens ...
  // why we need these three params? 
  // 1. cur : we are starting from the cur course/node
  // 2. graph : this is the adj List we constructed earlier, which stored the prerequisite information, key: class A, value : a list of classes you can take after taking class A 
 
  // 3: visited : int[] , which keep track of the visiting/visited status of each node/course. the default inital value for each element in the int[] is 0, which in our case means unexplored yet. there are two other numbers represent two other states. 1 means visiting, 2 means visited. 
  
  // one important thing is knowing the meaning of the visiting/ visited state. when a node is marked as visited and when it's marked as visiting. be very clear about this intuitivley and in code logic, (which i don't have this clear intuition of the state change)
  
  private boolean hasCycle(int cur, ArrayList<ArrayList<Integer>> graph, int[] visited){
    if(visited[cur] == 1){ // 1 means visiting 
      return true; // has cycle 
    }
    
    // haven't walked through any examples which evolves this case yet 
    if(visited[cur] == 2){  // 2 means visited , done visiting 
      return false;  // does not have cycle 
      
    }
    
    
    // when we first visiting a node, its default initial value is 0, which means waiting to be explored. and since we just start from this node, we mark it as visiting, since we haven't checked where it 's heading to.
    // my unvalidated assumption: if it doesnt have any neis, then its done here, mark it as visited. if it has neis, but all the neis are visited, then no need to visit the neis , so also mark the node as visited, since there's nothing left to do. if the nei is the visiting state, then we found a cycle? why???
    visited[cur] = 1;  // mark it as visiting 
    
    for(int next : graph.get(cur)){
      if(hasCycle(next, graph, visited)){
        return true; // has cycle
      }
    }
    
    visited[cur] = 2;  // after dfs, mark it as visited 
    return false;
  }
}









//////////////////////////////////////////////////////////// for the case we have a cycle 

-> 1 -> 2 - > 0 ->1
  
  2 <----
  |     |
 \|/    |
  0 - > 1 
  
input prerequisite pairs 
[[2, 1],
[1, 0],
[0, 2]]
  
input prerequiste pairs: [course A , one of the prerequisite for course A]
  
  
  



  
  
  
from emuerating from 0 , 


call hasCycle(0, graph, visited)
  current = 0;
  graph = [[1],[2],[0]]  (implicit key: course A, value : a list of courses you can take after taking course A)
  index 0, value [1],means 0 -> 1
  index 1, value[2], means 1 -> 2
  index 2, value[0], means 2 -> 0
    
  if we have more elements in the value[4, 5, 7 ], say index 2
    then 2 -> 4 
         2 -> 5 
         2 -> 7
    
initial default state: 
 int[] visited = 0 , 0, 0 
         index   0,  1, 2    
    
   
   
since index 0 is unexplored, mark it as 1, visiting
int[] visited = 1 , 0, 0 
         index  0,  1, 2 
   
   after taking course 0, we can take course 1 according to the graph(adjList).
   so we take a deep dive along this path, visit 1
   
   hasCycle(1, graph, visited)
   
   
    1 is unexplored before, since its default value is still 0, now we are visiting 1, so mark it as visiting, 
    
 int[] visited = 1, 1, 0 
         index   0, 1, 2 
   
   
    for(int next : graph.get(cur)){
      if(hasCycle(next, graph, visited)){
        return true; // has cycle
      }
    }

   
   after taking course 1, we can take course 2 according to the graph(adjList).
    so we take a deep dive along this path, visit 2
   
   hasCycle(2, graph, visited)
    
   
   
   
    2 is unexplored before, since its default value is still 0, now we are visiting 2, so mark it as visiting, 
    
 int[] visited = 1, 1, 1
         index   0, 1, 2
   
    after taking course 1, we can take course 0 according to the graph(adjList).
    so we take a deep dive along this path, visit 0
   
   hasCycle(0, graph, visited)
   
   
  0 is in the state of visiting according to the int[] visited, its value is 1 in the int[] visited. then we reached a cycle
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  //////////////////////////////////////// in the case we don't have a cycle 
  
  2
  |
 \|/
  0 - > 1 
  
  2 - > 0 ->1          
   input prerequiste pairs is 
  [ [0, 2],
   [1, 0]]
   
   
  input prerequiste pairs: [course A , one of the prerequisite for course A]
  








   
  our graph(adjList) looks like 
  
  graph = [[1],                 index 0, value [1],means 0 -> 1
           [ ],                 index 1, value[],  because 1 doesn't point to anything 
           [0]]                 index 2, value[0], means 2 -> 0
           
    
  (implicit key: course A, value : a list of courses you can take after taking course A)
  
 
   
  
  from emuerating from 0 , 


call hasCycle(0, graph, visited)
  current = 0;
   
initial default state: 
 int[] visited = 0 , 0, 0 
         index   0,  1, 2    
    
   
   
since index 0 is unexplored, mark it as 1, visiting
int[] visited = 1 , 0, 0 
         index  0,  1, 2 
   
   after taking course 0, we can take course 1 according to the graph(adjList).
   so we take a deep dive along this path, visit 1
   
   hasCycle(1, graph, visited)
   
   
    1 is unexplored before, since its default value is still 0, now we are visiting 1, so mark it as visiting, 
    
 int[] visited = 1, 1, 0 
         index   0, 1, 2 
   
  after taking course 1
graph.get(1) == [ ],  empty, so we don't do this for loop

'''
    for(int next : graph.get(cur)){
      if(hasCycle(next, graph, visited)){
        return true; // has cycle
      }
    }
'''
  we know 1 can not visit any more nodes/ take more courses, so we are done at course 1, so mark it as visited. 
  in the code, a node is marked as  visited  after  have explored the deepest path the current node can go, either after the for loop (hasCycle(next)) if this current node has nodes/courses to take, or the cur node doesn't have any nodes to explore and  can't go any further(the node doesnt point to anything, so in the graph, it does't even exist as a key, which means prerequisite, so this means the current node is not a prerequsite for any other nodes)  
  visited[1] = 2, 

   
 int[] visited = 1, 2, 0 
         index   0, 1, 2 
   

    

to do : 1. backtrack recovery the visited[i], 2. the intuitive idead and code logic for visited[cur] = 1
                                                                                       visited[cur] = 2








// bfs 
https://www.youtube.com/watch?v=zkTOIVUdW-I

course, prerequisite 

class Solution{
  public boolean canFinish(int numCourses, int[][] prerequisites){
    if(numCourses == 0 || prerequisites.length == 0) return true;
    
    int count = 0;
    int[] indegree = new int[numCourses];
    Queue<Integer> queue = new LinkedList<>();
    List<List<Integer>> list = new ArrayList<>();
    
    for(int i = 0; i < prerequisites.length; i++){
      indegree[prerequisites[i][0]]++;
    }
    
        
    for(int i = 0; i < numCourses; i++){
      if(indegree[i] == 0){
        count++;
        queue.offer(i);
      }
    }
    

    for(int i = 0; i < numCourses; i++){
      list.add(new ArrayList<>());
    }

    for(int i = 0; i < prerequisites.length; i++){
      list.get(prerequisites[i][1]).add(prerequisites[i][0]);
    }

    
    
    while(!queue.isEmpty()){
      int cur = queue.poll();
      for(int element : list.get(cur)){
        indegree[element]--;
        if(indegree[element] == 0){
          queue.offer(element);
          count++;
        }
      }
    }
    
    return count == numCourses;
  }
}










‘’‘’‘’‘’‘’‘’‘’‘’‘’‘’‘
  
  2
  |
 \|/
  0 - > 1 
  
  2 - > 0 ->1          
   input prerequiste pairs is 
  [ [0, 2],
   [1, 0]]
   
   
   
   int[] visited = new [numCourses.length];
   
   visited = {0, 0, 0}
   
   when we dont have a cycle 
  
  
  
  
 i = 0 
  visited 0 first, visited [0] = 0, we are vsiisting it, so set it as 1, so visited[0] = 1;
   
   visited = { 1, 0, 0}
   
   visite 1 from 0, call hasCycle(1, visited, graph)
   mark 1 as visiting , 1 doesn't have nodes to go visit next, so set visit[1] = 2 , which means visited
   return false, which means no cycle 
   
   so hasCycle(1, visited, graph) returns false;
   
   backtrack to last element, which is 0, set visited[0] = 2, visited
   return false;
   
   
i = 1
visited[1] = 2, visited , return false;


i = 2 

visit 2, visit[2] = 1, visiting 2 

hasCycle(2.next = 0, visited, graph)
0 is already visited, so return false;

so hasCycle(0, visited, graph) returns false;

back track visit[cur = 2] = 2; so set 2 as visited 
return false;

all the hasCycle(courses) returns false, which means no cycle, return true 
to canFinish 
   
   
   

猜你喜欢

转载自www.cnblogs.com/tobeabetterpig/p/9450563.html