Course Ordering with Concurrent Updates
Reported by candidates from Nuro's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.
The mistake that sinks a first attempt on this Nuro question, reported in September 2026, is treating it like plain Course Schedule and returning any valid order. It wants the lexicographically smallest one, recomputed on every GET_ORDER against the current graph. The 'concurrent updates' wording is a distraction, since the history is already one atomic sequence. Underneath it's a topological sort with a min-heap, plus a deduped edge set. If you blank on the heap detail during the live OA, StealthCoder runs invisibly as a safety net, but this one is very learnable tonight.
The problem
Maintain prerequisites for numCourses courses numbered 0 through numCourses - 1. Process a finite operation history: ["ADD_PREREQUISITE", course, prerequisite] adds the edge prerequisite -> course. Adding the same edge again has no effect and produces "null". ["GET_ORDER"] produces the lexicographically smallest order that completes all courses, serialized without spaces, such as "[0,1,2]". If the graph contains a cycle, produce "[]". Return one string for every operation. The history represents one legal linearization of concurrent calls: every update and query is atomic, and each query observes one complete committed graph state. Function courseOrderHistory(numCourses: int, operations: String[][]) → String[] Examples Example 1 numCourses = 4 operations = [["ADD_PREREQUISITE","1","0"],["ADD_PREREQUISITE","2","0"],["GET_ORDER"],["ADD_PREREQUISITE","0","1"],["GET_ORDER"]] return = ["null","null","[0,1,2,3]","null","[]"] The first query has two courses unlocked after 0, so the smaller label 1 comes first. The later reverse edge creates a cycle between 0 and 1. Example 2 numCourses = 3 operations = [["GET_ORDER"],["ADD_PREREQUISITE","2","1"],["ADD_PREREQUISITE","2","1"],["GET_ORDER"]] return = ["[0,1,2]","null","null","[0,1,2]"] The empty graph sorts by course label. The duplicate edge is ignored. Constraints 1 <= numCourses <= 2000. 1 <= operations.length <= 10000. Each course and prerequisite is in [0, numCourses - 1], and an update never uses the same course twice. Calls are linearizable; the provided history is their complete atomic order.
Reported by candidates. Source: FastPrep
Pattern and pitfall
Store edges in a set so duplicate ADD_PREREQUISITE calls return "null" without changing anything. Keep adjacency lists and rebuild indegrees on each query. Run Kahn's algorithm with a min-heap instead of a queue, so the smallest available course always goes next. If the output has fewer than numCourses entries, there's a cycle, so return "[]". Serialize with commas and no spaces. The pitfall is using a plain FIFO queue, which gives a valid order but not the smallest one. Another trap is mutating indegree arrays across queries. Copy or recompute them each time. Cost is O((V+E) log V) per query, and with 2000 courses and 10000 operations that's fine in practice. If the heap logic slips under pressure, StealthCoder is the hedge that can hand you the full solution live.
The honest play: practice the pattern, and have StealthCoder ready for the one you didn't see coming.
You can drill Course Ordering with Concurrent Updates 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 for the candidate who saw this exact problem leak two days before his OA and wondered if anyone had a play.
Get StealthCoderRelated leaked OAs
You've seen the question.
Make sure you actually pass Nuro's OA.
Nuro reuses patterns across OAs. Built for the candidate who saw this exact problem leak two days before his OA and wondered if anyone had a play. Works on HackerRank, CodeSignal, CoderPad, and Karat.
Course Ordering with Concurrent Updates FAQ
What's the trick in Course Ordering with Concurrent Updates?+
Kahn's topological sort using a min-heap, so you always take the smallest unlocked course. Rerun it on every GET_ORDER against the current edge set. If fewer than numCourses are output, a cycle exists and you return "[]".
Do I need to handle real concurrency?+
No. The problem says the history is one legal linearization and every operation is atomic. Just process the operations in the given order, one at a time. No locks or threads are needed.
How do I handle duplicate prerequisites?+
Keep a set of (prerequisite, course) pairs. If the pair already exists, return "null" and skip adding it. Otherwise add it to the set and the adjacency list, then return "null" anyway.
Why does a plain queue fail here?+
A FIFO queue produces a valid topological order, not the lexicographically smallest. With 1 and 2 both unlocked, insertion order might put 2 first. A min-heap guarantees the smallest label is always chosen.
How should I prepare for this in 48 hours?+
Write Kahn's algorithm from memory with a heap, then add the edge set and per-query recompute. Test both examples, including the cycle case and the empty graph. Practice the output formatting, since "[0,1,2]" with no spaces is easy to get wrong.