First Common Ancestor with Parent Pointers
Reported by candidates from Meta's online assessment. Pattern, common pitfall, and the honest play if you blank under the timer.
Meta reported this one in August 2026, and it looks like a tree problem but it's really two linked lists that merge. Each node's chain of parent pointers is a list ending at the root, and you're finding where the two lists join. If you've got an OA invite, this is the one to nail in your head tonight. The O(1) space rule kills the hash set shortcut, so you need the depth-align trick. StealthCoder sits invisibly on your screen as a safety net if you blank on the live OA, but the logic here is short enough to own.
The problem
A rooted tree is represented by an integer array parent. Nodes are numbered from 0 through parent.length - 1; parent[i] is the parent of node i, and the single root has parent -1. Child pointers are implied by the same tree. Given node indices first and second, return their first common ancestor when walking upward from the two nodes. A node is considered an ancestor of itself, so if one selected node is an ancestor of the other, return that selected node. The two selected nodes may be equal. Use O(1) auxiliary space. You may determine each depth by following parent links, lift the deeper node until both depths match, and then move both nodes upward until they meet. Function firstCommonAncestor(parent: int[], first: int, second: int) → int Examples Example 1 parent = [-1,0,0,1,1,2,2] first = 3 second = 4 return = 1 Nodes 3 and 4 are siblings whose nearest common ancestor is node 1. Example 2 parent = [-1,0,0,1,1,2,2] first = 1 second = 4 return = 1 Node 1 is an ancestor of node 4 and counts as its own ancestor. Example 3 parent = [-1,0,0,1,1,2,2] first = 3 second = 6 return = 0 The nodes lie in different child subtrees of the root, so their first common ancestor is node 0. Constraints 1 <= parent.length <= 100000. parent describes exactly one valid rooted tree: one entry is -1, and following parent links from every other node reaches that root. 0 <= first, second < parent.length. The algorithm must use O(1) auxiliary space.
Reported by candidates. Source: FastPrep
Pattern and pitfall
The trick is the same as finding the intersection of two linked lists. Walk up from each node to compute its depth. Lift the deeper node until both depths match. Then move both up one step at a time until they land on the same node. That node is the answer. Equal nodes and the ancestor-of-itself case fall out naturally: if first is an ancestor of second, lifting second lands exactly on first, and they match immediately. The common pitfall is reaching for a visited set, which breaks the O(1) space requirement. Another is off-by-one when lifting, so lift by the depth difference exactly. Depth counting is O(n) per node and the whole thing is O(n) time. With 100000 nodes, use loops, not recursion. If you freeze in the live OA, StealthCoder can hand you the loop structure, but you only need three small loops.
If this hits your live OA and you blank, StealthCoder solves it in seconds, invisible to the proctor.
You can drill First Common Ancestor with Parent Pointers 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 would have shipped this the night before his JPMorgan OA if he'd had it.
Get StealthCoderRelated leaked OAs
You've seen the question.
Make sure you actually pass Meta's OA.
Meta reuses patterns across OAs. Built by an Amazon engineer who would have shipped this the night before his JPMorgan OA if he'd had it. Works on HackerRank, CodeSignal, CoderPad, and Karat.
First Common Ancestor with Parent Pointers FAQ
What's the trick for First Common Ancestor with Parent Pointers?+
Treat each node's parent chain as a linked list and find where they merge. Compute both depths, lift the deeper node by the difference, then step both up together until they're equal. No extra memory needed, which is what the constraint demands.
Can I use a hash set of ancestors instead?+
It works logically but violates the O(1) auxiliary space requirement. Store first's ancestors, walk up from second, return the first hit. It's O(n) space, so the depth-alignment approach is what the problem wants.
How do I handle when one node is the ancestor of the other?+
You don't need special code. After lifting the deeper node to the shallower depth, both pointers sit on the same node if one is the ancestor of the other. The meeting loop exits immediately and returns it. Same for first equal to second.
Will recursion be a problem with 100000 nodes?+
Yes, a skewed tree can be 100000 deep and blow the stack. Use iterative while loops following parent[i] until you hit -1. It's also cleaner and keeps auxiliary space constant.
How should I prepare for this in 48 hours?+
Write the three-loop solution from scratch twice: depth function, lift loop, meet loop. Then test the three examples plus first equals second and root as an answer. Also review linked list intersection, since it's the identical idea.