Friday, May 27, 2016

Course Schedule -- LeetCode

[Question]
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:
2, [[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.
2, [[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 is equivalent to the question of finding a circle in a Directed Graph (DiGraph). Using DFS and find if one path will cross itself.

Another approach is to use BFS. Define a node without incoming going edges as Root Node. The assumption is a DiGraph without Root Node must have a circle -- this can be proven by mathematical induction. Therefore, remove Root Node one by one from the DiGraph one by one; if the reminding graph does not have Root Node, it has a circle. Time complexity O(E+V).

[Solutions]
//-- DFS --
class Solution {
public:
    vector<unordered_set<int> > graph;
    vector<bool> visited;
   
    bool dfs_findCircle(int i, unordered_set<int> &path) {
        if (visited[i]) {
            return (path.find(i)!=path.end());
        }
        visited[i] = true;
        path.insert(i);
        for(auto j : graph[i]) {
            if (dfs_findCircle(j, path)) return true;
        }
        path.erase(i);
        return false;
    }
   
    bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
        if (prerequisites.empty()) return true;
        visited.resize(numCourses, false);
        graph.resize(numCourses, unordered_set<int>() );
        for (auto p: prerequisites) {
            graph[p.first].insert(p.second);
        }
        for (int i=0; i<numCourses; i++) {
            if (!visited[i]) {
                unordered_set<int> set;
                bool found = dfs_findCircle(i, set);
                if (found) return false;
            }
        }
        return true;
    }
}; 
 
//-- BFS --
class Solution {
public:
    bool canFinish(int numCourses, vector<pair<int, int>>& prerequisites) {
        if (prerequisites.empty()) return true;
       
        unordered_set <int> src;
        unordered_map <int, unordered_set<int>> fwd, bwd;
       
        for (auto pair: prerequisites) {
            src.insert(pair.first);
            fwd[pair.first].insert(pair.second);
            bwd[pair.second].insert(pair.first);
        }
       
        for (auto& x: bwd) src.erase(x.first);

        while (!src.empty()) {
            unordered_set<int> src1;
            for(auto x: src) {
                for(auto y: fwd[x]) {
                    bwd[y].erase(x);
                    if (bwd[y].empty()) {
                        src1.insert(y);
                    }
                }
                fwd.erase(x);
            }
            src = src1;
        }
           
        return fwd.empty();
    }
};

No comments:

Post a Comment