Reported September 2026
Ripplinggraph

Common Ancestors in a Directed Acyclic Graph

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

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

The data structure that decides this one is the reversed adjacency list. Rippling reportedly asked "Common Ancestors in a Directed Acyclic Graph" in September 2026, and it looks scarier than it is. You get a DAG of up to 10^5 nodes, two targets, and you return every strict ancestor of both, sorted. It's a graph traversal problem wearing a family-tree costume. If you've got an OA coming, this is a clean 15-minute solve once you see the shape. StealthCoder sits invisibly as a safety net on the live OA if your mind goes blank, but the idea below is short enough to carry in your head.

The problem

Nodes are labeled from 0 through nodeCount - 1. Each row [parent, child] in parentEdges is a directed parent relationship, and the graph is acyclic.
Return every strict ancestor of both first and second, sorted increasingly. A node is not its own ancestor.

Function
commonAncestors(nodeCount: int, parentEdges: int[][], first: int, second: int) → int[]

Examples
Example 1
nodeCount = 6
parentEdges = [[0,2],[1,2],[1,3],[2,4],[3,4],[4,5]]
first = 4
second = 5
return = [0,1,2,3]
Every ancestor of 4 is also an ancestor of 5.
Example 2
nodeCount = 5
parentEdges = [[0,2],[1,2],[1,3]]
first = 2
second = 3
return = [1]
Node 1 reaches both targets.
Example 3
nodeCount = 4
parentEdges = [[0,1],[2,3]]
first = 1
second = 3
return = []
The targets are in disconnected components.

Constraints
1 <= nodeCount <= 10^5.
0 <= parentEdges.length <= 2 * 10^5.
The edges form a directed acyclic graph and contain no duplicates.

Reported by candidates. Source: FastPrep

Pattern and pitfall

Build a child-to-parents map from parentEdges. Run a BFS or iterative DFS from first over that reversed graph and collect every node you reach, excluding first itself. Do the same from second. Intersect the two sets, then sort the result. That's O(V + E) for the traversals plus O(k log k) for sorting. The pitfalls are real. Don't use recursion on 10^5 nodes, since a long chain will blow the stack in many languages. Don't include first or second in their own ancestor sets. Note that in Example 1, node 4 is an ancestor of 5, but 4 is first, so it stays out of the answer. Also don't run a full ancestor search per node, that goes quadratic. If you freeze during the live OA, StealthCoder can surface the reversed-graph approach fast, but you should be able to write it yourself.

StealthCoder is the hedge for the one pattern you didn't drill. It runs invisibly during the screen share.

If this hits your live OA

You can drill Common Ancestors in a Directed Acyclic Graph 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. If you're reading this with an OA window open, you're who this was built for.

Get StealthCoder

Related leaked OAs

⏵ The honest play

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

Rippling reuses patterns across OAs. If you're reading this with an OA window open, you're who this was built for. Works on HackerRank, CodeSignal, CoderPad, and Karat.

Common Ancestors in a Directed Acyclic Graph FAQ

What's the trick to Common Ancestors in a DAG?+

Reverse the edges. Store each child's parents, then traverse upward from each target and collect visited nodes. Intersect the two visited sets and sort. Because the graph is acyclic, a plain visited set keeps each traversal linear in nodes plus edges.

Should I use BFS or DFS here?+

Either works. Use an iterative version with an explicit stack or queue, because nodeCount can reach 10^5 and a deep chain would overflow recursion in most languages. BFS with a deque is the safest default and easy to write correctly.

Is a node its own ancestor in this problem?+

No. The statement says strict ancestors only. Start the traversal from the target's parents, or remove the target from its set. In Example 1, node 4 is an ancestor of 5 but isn't returned, because 4 is the first target.

What's the time complexity I should state?+

Building the parent map is O(V + E). Two traversals are O(V + E) each. Intersecting sets is linear, and sorting the result is O(k log k) where k is the number of common ancestors. Overall it's near linear, which fits 2 * 10^5 edges easily.

How do I prepare for this in 48 hours?+

Write the reversed-graph traversal from scratch twice. Test it on the three examples, especially the disconnected case that returns an empty list. Then practice general graph reachability problems so adjacency lists, visited sets, and iterative traversal feel automatic.

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

OA at Rippling?
Invisible during screen share
Get it