207. Course Schedule
mediumAsked at PinterestCourse Schedule is Pinterest's go-to cycle-detection problem: given course prerequisites as edges, decide whether you can finish every course. The interviewer wants a topological sort or DFS three-color cycle check — pick one and execute it cleanly.
By Sam K., Founder, InterviewChamp.AI · Last verified
Source citations
Public interview reports confirming this problem appears in Pinterest loops.
- Glassdoor (2026-Q1)— Pinterest SWE onsite reports list Course Schedule as the graph round, often paired with Course Schedule II.
- LeetCode Pinterest tag (2026-Q1)— On the Pinterest company-tagged problem list.
Problem
There are a total of numCourses courses labeled from 0 to numCourses - 1. You are given an array prerequisites where prerequisites[i] = [a_i, b_i] indicates that you must take course b_i first if you want to take course a_i. Return true if you can finish all courses. Otherwise, return false.
Constraints
1 <= numCourses <= 20000 <= prerequisites.length <= 5000prerequisites[i].length == 20 <= a_i, b_i < numCoursesAll pairs are unique.
Examples
Example 1
numCourses = 2, prerequisites = [[1,0]]trueExample 2
numCourses = 2, prerequisites = [[1,0],[0,1]]falseExplanation: Cycle: 0 needs 1, 1 needs 0.
Approaches
1. Kahn's algorithm (BFS topological sort, optimal)
Compute in-degree per node. Push every zero-in-degree node into a queue. Pop, decrement neighbors' in-degree, push new zeros. If processed count equals numCourses, no cycle.
- Time
- O(V + E)
- Space
- O(V + E)
function canFinish(numCourses, prerequisites) {
const graph = Array.from({ length: numCourses }, () => []);
const indeg = new Array(numCourses).fill(0);
for (const [a, b] of prerequisites) {
graph[b].push(a);
indeg[a] += 1;
}
const q = [];
for (let i = 0; i < numCourses; i++) if (indeg[i] === 0) q.push(i);
let processed = 0;
while (q.length) {
const u = q.shift();
processed += 1;
for (const v of graph[u]) {
indeg[v] -= 1;
if (indeg[v] === 0) q.push(v);
}
}
return processed === numCourses;
}Tradeoff: Iterative, easy to reason about, no recursion-depth risk. Standard answer at Pinterest. Edge: q.shift() is O(n) — for very large graphs use a head pointer.
2. DFS three-color cycle detection
Track each node's state: 0 = unvisited, 1 = in current DFS path, 2 = fully processed. If DFS hits a 1-marked node, cycle.
- Time
- O(V + E)
- Space
- O(V + E)
function canFinishDfs(numCourses, prerequisites) {
const graph = Array.from({ length: numCourses }, () => []);
for (const [a, b] of prerequisites) graph[a].push(b);
const state = new Array(numCourses).fill(0); // 0=white, 1=gray, 2=black
function dfs(u) {
if (state[u] === 1) return false; // cycle
if (state[u] === 2) return true;
state[u] = 1;
for (const v of graph[u]) if (!dfs(v)) return false;
state[u] = 2;
return true;
}
for (let i = 0; i < numCourses; i++) if (!dfs(i)) return false;
return true;
}Tradeoff: Slightly shorter to write, but recursion-depth bites on long chains (2000 courses is fine in V8; longer DAGs need an iterative DFS). The three-color invariant is the part to narrate.
Pinterest-specific tips
Pinterest interviewers grade on whether you reach for the topological-sort frame immediately when you see 'prerequisites.' Lead with Kahn's because it's iterative and queue-based — easier to extend to the LeetCode 210 follow-up (return the actual order, not just the boolean). Mention DFS three-color as 'I could also do this with DFS using a gray/black state' to signal you know both.
Common mistakes
- Building the graph in the wrong direction — prereqs[i] = [a, b] means b -> a (you take b before a), so b is the parent in the topo-sort.
- Marking nodes as 'visited' instead of three-color in the DFS version — visited alone can't distinguish 'in this path' from 'fully done', so cycles are missed.
- Forgetting disconnected components — every node needs an entry point, not just those reachable from node 0.
- Returning the wrong sentinel when the BFS finishes: processed === numCourses, not q.length === 0.
Follow-up questions
An interviewer at Pinterest may pivot to one of these next:
- Course Schedule II (LeetCode 210): return the actual order, not just feasibility.
- Alien Dictionary (LeetCode 269): topo-sort with implicit edges from word ordering.
- Detect ALL cycles, not just whether one exists.
- Streaming: prerequisites arrive online — maintain feasibility with each addition.
Solve it now
Free. No sign-up. Python and JavaScript run instantly in your browser.
FAQ
Should I use BFS or DFS?
Either passes correctness. BFS (Kahn's) is the safer default at Pinterest because it generalizes naturally to the order-returning follow-up. DFS three-color is more concise but recursion-heavy.
Why does Pinterest specifically ask this?
Many Pinterest infra problems reduce to dependency ordering — build systems, data pipelines, board feature dependencies. Topo-sort is the primitive that surfaces repeatedly.
Free learning resources
Curated free links for this problem.