LeetCode – Course Schedule (Java)

There are a total of n courses you have to take, labeled from 0 to n – 1. Some courses may have 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, is it possible for you to finish all courses?

For example, given 2 and [[1,0]], there are a total of 2 courses to take. To take course 1 you should have finished course 0. So it is possible.

For another example, given 2 and [[1,0],[0,1]], there are a total of 2 courses to take. To take course 1 you should have finished course 0, and to take course 0 you should also have finished course 1. So it is impossible.

Analysis

This problem can be converted to finding if a graph contains a cycle.

Java Solution 1 – BFS

This solution uses breath-first search and it is easy to understand.

public boolean canFinish(int numCourses, int[][] prerequisites) {
    if(prerequisites == null){
        throw new IllegalArgumentException("illegal prerequisites array");
    }
 
    int len = prerequisites.length;
 
    if(numCourses == 0 || len == 0){
        return true;
    }
 
    // counter for number of prerequisites
    int[] pCounter = new int[numCourses];
    for(int i=0; i<len; i++){
        pCounter[prerequisites[i][0]]++;
    }
 
    //store courses that have no prerequisites
    LinkedList<Integer> queue = new LinkedList<Integer>();
    for(int i=0; i<numCourses; i++){
        if(pCounter[i]==0){
            queue.add(i);
        }
    }
 
    // number of courses that have no prerequisites
    int numNoPre = queue.size();
 
    while(!queue.isEmpty()){
        int top = queue.remove();
        for(int i=0; i<len; i++){
            // if a course's prerequisite can be satisfied by a course in queue
            if(prerequisites[i][1]==top){
                pCounter[prerequisites[i][0]]--;
                if(pCounter[prerequisites[i][0]]==0){
                    numNoPre++;
                    queue.add(prerequisites[i][0]);
                }
            }
        }
    }
 
    return numNoPre == numCourses;
}

Java Solution 2 – DFS

public boolean canFinish(int numCourses, int[][] prerequisites) {
    if(prerequisites == null){
        throw new IllegalArgumentException("illegal prerequisites array");
    }
 
    int len = prerequisites.length;
 
    if(numCourses == 0 || len == 0){
        return true;
    }
 
    //track visited courses
    int[] visit = new int[numCourses];
 
    // use the map to store what courses depend on a course 
    HashMap<Integer,ArrayList<Integer>> map = new HashMap<Integer,ArrayList<Integer>>();
    for(int[] a: prerequisites){
        if(map.containsKey(a[1])){
            map.get(a[1]).add(a[0]);
        }else{
            ArrayList<Integer> l = new ArrayList<Integer>();
            l.add(a[0]);
            map.put(a[1], l);
        }
    }
 
    for(int i=0; i<numCourses; i++){
        if(!canFinishDFS(map, visit, i))
            return false;
    }
 
    return true;
}
 
private boolean canFinishDFS(HashMap<Integer,ArrayList<Integer>> map, int[] visit, int i){
    if(visit[i]==-1) 
        return false;
    if(visit[i]==1) 
        return true;
 
    visit[i]=-1;
    if(map.containsKey(i)){
        for(int j: map.get(i)){
            if(!canFinishDFS(map, visit, j)) 
                return false;
        }
    }
 
    visit[i]=1;
 
    return true;
}

Topological Sort Video from Coursera.

7 thoughts on “LeetCode – Course Schedule (Java)”

  1. public class Courses {

    private static boolean canFinish(int num, int[][] prerequisites){
    Set set = new HashSet();
    for(int i=0; i<num; i++){
    if(dfs(i, prerequisites, set)) {
    return true;
    }
    }
    return false;
    }

    private static boolean dfs(int start, int[][] prerequisites, Set set) {
    set.add(start);
    int[] dependencies = getDependencies(start, prerequisites);
    for(int i: dependencies) {
    if(set.contains(i)) {
    return true;
    } else if(dfs(i, prerequisites, set)) {
    return true;
    }
    }
    set.remove(start);
    return false;
    }

    private static int[] getDependencies(int start, int[][] prerequisites) {
    List al = new ArrayList();
    for(int i=0; i<prerequisites.length; i++) {
    if(prerequisites[i][0] == start) {
    al.add(prerequisites[i][1]);
    }
    }
    int[] ret = new int[al.size()];
    for(int i=0; i<al.size(); i++) {
    ret[i] = al.get(i);
    }
    return ret;
    }

    public static void main(String[] args) {
    int[][] testcase = {{0,1},{1,2},{2,0},{4,0},{3,4}};
    int[][] testcase2 = {{0,1},{1,2},{2,4},{0,4},{4,3}};
    int[][] testcase3 = {{0,1},{1,0}};
    int[][] testcase4 = {{0,1}};
    int[][] testcase5 = {{0,1},{1,2},{2,4},{0,4},{4,3},{3,0}};
    System.out.println(canFinish(testcase5.length, testcase5));
    }

    }

  2. Isn’t going to much easier to read and code if a Graph holder class is defined and its object is populated with the input i.e. prerequisites. Graph class will hold the adjacency lists for every course.

    And basically this problem will boil down to “Detect cycle in a DIRECTED graph”.

  3. The problem declaration is ambiguous. If “one node is reachable only if ALL of its parents are reached”,then your detecting cycle solution is right. Else if “one node is reachable if ONE of its parent is reached”, then soluition is much simpler, because you only need to find “independent nodes”, and to see if they are connected to other nodes.

Leave a Comment