Problem

Given numCourses and prerequisites pairs [a, b] meaning b must be taken before a, return true if you can finish all courses.

Example

Input:  numCourses = 2, prerequisites = [[1,0]]
Output: true

Solution

Detect a cycle in the directed graph using DFS with three colors (white, gray, black).

def can_finish(num_courses, prerequisites):
    graph = [[] for _ in range(num_courses)]
    for a, b in prerequisites:
        graph[b].append(a)
    state = [0] * num_courses
    def dfs(node):
        if state[node] == 1: return False
        if state[node] == 2: return True
        state[node] = 1
        for nei in graph[node]:
            if not dfs(nei): return False
        state[node] = 2
        return True
    return all(dfs(i) for i in range(num_courses))
function canFinish(n, pre) {
    const graph = Array.from({length: n}, () => []);
    for (const [a, b] of pre) graph[b].push(a);
    const state = new Array(n).fill(0);
    function dfs(node) {
        if (state[node] === 1) return false;
        if (state[node] === 2) return true;
        state[node] = 1;
        for (const nei of graph[node]) if (!dfs(nei)) return false;
        state[node] = 2;
        return true;
    }
    for (let i = 0; i < n; i++) if (!dfs(i)) return false;
    return true;
}
bool dfs(int node, vector<vector<int>>& g, vector<int>& state) {
    if (state[node] == 1) return false;
    if (state[node] == 2) return true;
    state[node] = 1;
    for (int nei : g[node]) if (!dfs(nei, g, state)) return false;
    state[node] = 2;
    return true;
}
bool canFinish(int n, vector<vector<int>>& pre) {
    vector<vector<int>> g(n);
    for (auto& p : pre) g[p[1]].push_back(p[0]);
    vector<int> state(n, 0);
    for (int i = 0; i < n; i++) if (!dfs(i, g, state)) return false;
    return true;
}
public boolean canFinish(int n, int[][] pre) {
    List<List<Integer>> g = new ArrayList<>();
    for (int i = 0; i < n; i++) g.add(new ArrayList<>());
    for (int[] p : pre) g.get(p[1]).add(p[0]);
    int[] state = new int[n];
    for (int i = 0; i < n; i++) if (!dfs(i, g, state)) return false;
    return true;
}
private boolean dfs(int node, List<List<Integer>> g, int[] state) {
    if (state[node] == 1) return false;
    if (state[node] == 2) return true;
    state[node] = 1;
    for (int nei : g.get(node)) if (!dfs(nei, g, state)) return false;
    state[node] = 2;
    return true;
}

Complexity

  • Time: O(V + E)
  • Space: O(V + E)

Explanation

State 0 = unvisited, 1 = in current DFS path, 2 = fully processed. If we hit a node in state 1, we found a cycle.

Share this article

Comments

Join the discussion. Got a question, found an issue, or want to share your experience?

Leave a Comment

Your email stays private. We just use it for replies.

Nothing to preview yet.

Use **bold**, *italic*, `code`, ```code blocks```, [link](url), > quote, - list