Dependency-Aware Task Scheduler
Reported by candidates from Rippling's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.
Rippling reported this one in October 2026, and the constraints are the tell. Up to 20000 tasks and 50000 edges means you can't rescan the whole list every time you pick the next task. That's the O(n^2) trap. It's a topological sort with a twist: the ready set is a priority queue, not a plain FIFO. Filter first, build indegrees on retained tasks only, then pull the best ready task each round. If you're staring at it with the clock running, StealthCoder is the safety net that runs invisibly during the live OA and hands you the structure if you blank.
The problem
You are given unique task identifiers, dependency edges, integer priorities, and a filter decision for every task. A dependency [before, after] means before must appear before after. Only tasks whose included value is true participate. Ignore a dependency edge when either endpoint is filtered out. Repeatedly choose a currently ready task with the greatest priority; break ties by the lexicographically smaller task identifier. Return the deterministic schedule. If the retained dependency graph contains a cycle, return an empty array. Function scheduleTasks(taskIds: String[], dependencies: String[][], priorities: int[], included: boolean[]) → String[] Examples Example 1 taskIds = ["extract","clean","load","audit"] dependencies = [["extract","clean"],["clean","load"]] priorities = [2,5,4,9] included = [true,true,true,true] return = ["audit","extract","clean","load"] Audit is initially ready with the greatest priority. The remaining dependency chain must then run in order. Example 2 taskIds = ["a","b","c"] dependencies = [["a","b"],["b","c"]] priorities = [1,10,5] included = [false,true,true] return = ["b","c"] Filtering removes task a and its incident edge. Task b is then ready before c. Example 3 taskIds = ["a","b"] dependencies = [["a","b"],["b","a"]] priorities = [1,2] included = [true,true] return = [] No retained task has zero indegree, so the retained graph is cyclic. Constraints 1 <= taskIds.length == priorities.length == included.length <= 20000. Task identifiers are unique nonempty ASCII strings. -10^9 <= priorities[i] <= 10^9. 0 <= dependencies.length <= 50000; every edge contains two known, different identifiers and edges are distinct.
Reported by candidates. Source: FastPrep
Pattern and pitfall
The trick is Kahn's algorithm with a heap. Drop filtered tasks, then drop any edge touching one. Build an adjacency list and indegree counts for retained tasks only. Push every zero-indegree task into a heap ordered by priority descending, then task id ascending. Pop, append to the result, decrement neighbors, and push any that hit zero. At the end, if the result length is less than the retained count, there's a cycle, so return an empty array. Pitfalls: counting indegree for edges with a filtered endpoint, which makes valid tasks look blocked. Also getting the comparator backwards, since priority is max-first but ids are min-first. Compare ids as plain strings. Complexity is O((n+m) log n). If you blank on the comparator or the cycle check mid-assessment, StealthCoder can surface a clean reference solution without anyone seeing it on screen.
Drill it cold or hedge it with StealthCoder. Either way, don't walk into the OA hoping you remember the trick.
You can drill Dependency-Aware Task Scheduler 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. Made for the candidate who got the OA invite this morning and has 72 hours, not six months.
Get StealthCoderRelated leaked OAs
You've seen the question.
Make sure you actually pass Rippling's OA.
Rippling reuses patterns across OAs. Made for the candidate who got the OA invite this morning and has 72 hours, not six months. Works on HackerRank, CodeSignal, CoderPad, and Karat.
Dependency-Aware Task Scheduler FAQ
What's the core trick in the Rippling dependency-aware task scheduler?+
Kahn's topological sort, but swap the plain queue for a heap. Ready tasks are ordered by highest priority first, then lexicographically smaller id. Filter tasks and their edges up front, then run the heap loop and check whether every retained task got scheduled.
How do I detect the cycle case?+
Count retained tasks before you start. After the heap loop ends, compare the result length to that count. If it's smaller, some tasks never reached zero indegree, so the retained graph has a cycle. Return an empty array. Don't return a partial schedule.
Why can't I just sort by priority and fix dependencies after?+
Priority only applies among currently ready tasks. A high-priority task with an unmet dependency can't go yet. Sorting once ignores that, and rescanning for the best ready task each step is O(n^2), which is too slow at 20000 tasks.
How should I handle filtered-out tasks and their edges?+
Build a set of included ids. When reading dependencies, skip any edge where either endpoint isn't included. Only count indegree and adjacency for the survivors. Forgetting this is the most common bug, since it leaves ghost blockers on valid tasks.
How do I prepare for this in 48 hours?+
Write Kahn's algorithm from memory twice, once with a queue and once with a heap and a custom comparator. Practice a tuple key like (-priority, id). Then test the three given examples, especially the cycle and filter cases, since those catch most mistakes.