Reported December 2022
Chainalysisgraph

Course Schedule II

Reported by candidates from Chainalysis's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.

Get StealthCoderRuns invisibly during the live Chainalysis OA. Under 2s to a working solution.
Founder's read

Strip the course-catalog story off this Chainalysis OA, reported in December 2022, and it's a topological sort with one twist: when several courses are free, take the smallest label. That twist changes your data structure. If the invite is sitting in your inbox, this is a known shape, not a surprise. Build the graph, track in-degrees, and process in order. If you blank on the live assessment, StealthCoder runs invisibly on your desktop and can hand you the working solution while the screen share stays clean.

The problem

You are given numCourses courses labeled from 0 to numCourses - 1 and a list of prerequisite pairs. Each pair [course, prerequisite] means that prerequisite must be completed before course.
Return an order in which all courses can be completed. Whenever several courses have no remaining prerequisites, choose the smallest numbered course next. If the prerequisite graph contains a cycle and completing every course is impossible, return an empty array.

Function
findOrder(numCourses: int, prerequisites: int[][]) → int[]

Examples
Example 1
numCourses = 2
prerequisites = [[1, 0]]
return = [0, 1]
Course 0 has no prerequisite. Completing it unlocks course 1.
Example 2
numCourses = 4
prerequisites = [[1, 0], [2, 0], [3, 1], [3, 2]]
return = [0, 1, 2, 3]
After course 0, both courses 1 and 2 are available. The smaller course is chosen first.
Example 3
numCourses = 2
prerequisites = [[1, 0], [0, 1]]
return = []
The two courses form a cycle, so no complete ordering exists.

Constraints
1 <= numCourses <= 2000
0 <= prerequisites.length <= 5000
Each prerequisite pair contains two distinct course labels in the range [0, numCourses - 1].
All prerequisite pairs are unique.
When multiple courses are available, choose the smallest course label first.

Reported by candidates. Source: FastPrep

Pattern and pitfall

The trick is Kahn's algorithm with a min-heap instead of a plain queue. Build an adjacency list from each [course, prerequisite] pair, so prerequisite points to course, and count in-degrees. Push every course with in-degree 0 into a min-heap. Pop the smallest, append it to the result, decrement the in-degree of its neighbors, and push any that hit 0. If the result length ends up below numCourses, there's a cycle, so return an empty array. The common pitfall is using a regular queue, which passes Example 1 and fails the smallest-label tie-break. Another is reversing the edge direction because the pair is [course, prerequisite]. Complexity is O((V + E) log V), fine for 2000 courses and 5000 edges. StealthCoder is your hedge if the heap detail slips under pressure during the live OA.

If you see this problem in your OA tomorrow, the play is to recognize the pattern in 30 seconds. StealthCoder buys you that recognition.

If this hits your live OA

You can drill Course Schedule II cold, or you can hedge it. StealthCoder runs invisibly during screen share and surfaces a working solution in under 2 seconds. The proctor sees the IDE. They don't see what's behind it. Built by an Amazon engineer who passed his OA cold and still thinks the filter is broken.

Get StealthCoder

Related leaked OAs

⏵ Practice the LeetCode equivalent

This OA pattern shows up on LeetCode as course schedule ii. If you have time before the OA, drill that.

⏵ The honest play

You've seen the question. Make sure you actually pass Chainalysis's OA.

Chainalysis reuses patterns across OAs. Built by an Amazon engineer who passed his OA cold and still thinks the filter is broken. Works on HackerRank, CodeSignal, CoderPad, and Karat.

Course Schedule II FAQ

What's the trick in Course Schedule II at Chainalysis?+

It's a topological sort. Count in-degrees, start with courses that have none, and release neighbors as you finish each course. The Chainalysis version adds a tie-break, so use a min-heap rather than a FIFO queue to always pick the smallest available label.

Why does a plain queue fail here?+

A plain queue processes courses in the order they became available, not by label. Example 2 hides this because it happens to work. With other inputs, a larger label can sit ahead of a smaller one and your output will be wrong. The min-heap fixes it.

How do I detect the cycle case?+

Count how many courses you output. If the count is less than numCourses, some courses never reached in-degree 0, which means they sit in a cycle. Return an empty array. No separate cycle-detection pass is needed with Kahn's algorithm.

Can I use DFS instead?+

You can, with three-color marking and reversed post-order, but the smallest-label tie-break is awkward to get right in DFS. Kahn's with a heap handles it naturally. For a timed OA, pick the approach that makes the tie-break trivial.

How do I prepare in 48 hours for this?+

Write Kahn's algorithm from scratch twice, once with a queue and once with a heap. Test the cycle case and a graph with no prerequisites. Watch the edge direction on [course, prerequisite]. That covers the pattern, and it's the same skeleton as most dependency-ordering questions.

Problem reported by candidates from a real Online Assessment. Sourced from a publicly-available candidate-aggregated repository. Not affiliated with Chainalysis.

OA at Chainalysis?
Invisible during screen share
Get it