Find root IDs and paths
Company: ZipHQ
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: Medium
Interview Round: Technical Screen
Quick Answer: This question evaluates understanding of graph/tree relationships, identification of root nodes, and path reconstruction from parent references, assessing algorithmic reasoning and data-structure familiarity.
Find Root IDs
Constraints
- 0 <= number of blocks <= 10^5
- Each id is a non-empty string and ids are unique.
- parentId is either null or a string (which may or may not match an existing id).
- Return roots in the order their blocks appear in the input.
Examples
Input: ([{"id": "a", "parentId": None}, {"id": "b", "parentId": "a"}, {"id": "c", "parentId": "b"}],)
Expected Output: ['a']
Explanation: Only 'a' has no parent; 'b' and 'c' chain up to it.
Input: ([{"id": "a", "parentId": None}, {"id": "b", "parentId": None}, {"id": "c", "parentId": "a"}, {"id": "d", "parentId": "b"}],)
Expected Output: ['a', 'b']
Explanation: Two separate trees, so two roots, returned in input order.
Input: ([{"id": "x", "parentId": "missing"}, {"id": "y", "parentId": "x"}],)
Expected Output: ['x']
Explanation: 'x' references a parent 'missing' that does not appear in the input, so 'x' is a root (dangling reference).
Input: ([],)
Expected Output: []
Explanation: Empty input yields no roots.
Input: ([{"id": "solo", "parentId": None}],)
Expected Output: ['solo']
Explanation: A single block with null parent is a root.
Input: ([{"id": "a", "parentId": "ghost"}, {"id": "b", "parentId": None}, {"id": "c", "parentId": "a"}, {"id": "d", "parentId": "zzz"}],)
Expected Output: ['a', 'b', 'd']
Explanation: 'a' (dangling 'ghost'), 'b' (null), and 'd' (dangling 'zzz') are all roots; 'c' chains to 'a'.
Hints
- First collect every block's id into a hash set so you can test 'does this parent exist?' in O(1).
- A block is a root when parentId is null OR parentId is not in that set — handle the dangling-reference case explicitly.
- Preserve input order by iterating the blocks a second time rather than iterating the set.
Path From Root To Target
Constraints
- 0 <= number of blocks <= 10^5
- ids are unique, non-empty strings.
- parentId is null or a string; a dangling parentId marks a root.
- If targetId is not one of the block ids, return an empty list.
- The path is returned root-first, target-last.
Examples
Input: ([{"id": "a", "parentId": None}, {"id": "b", "parentId": "a"}, {"id": "c", "parentId": "b"}], "c")
Expected Output: ['a', 'b', 'c']
Explanation: Walk c -> b -> a, then reverse to root-first order.
Input: ([{"id": "a", "parentId": None}, {"id": "b", "parentId": "a"}, {"id": "c", "parentId": "b"}], "a")
Expected Output: ['a']
Explanation: The target is itself a root, so the path is just [a].
Input: ([{"id": "x", "parentId": "missing"}, {"id": "y", "parentId": "x"}, {"id": "z", "parentId": "y"}], "z")
Expected Output: ['x', 'y', 'z']
Explanation: 'x' has a dangling parent so it is the root; path is x -> y -> z.
Input: ([{"id": "a", "parentId": None}, {"id": "b", "parentId": "a"}], "missing")
Expected Output: []
Explanation: The target id is not present in the input, so return an empty list.
Input: ([{"id": "solo", "parentId": None}], "solo")
Expected Output: ['solo']
Explanation: Single-node tree where the target is the root.
Input: ([{"id": "r", "parentId": None}, {"id": "a", "parentId": "r"}, {"id": "b", "parentId": "a"}, {"id": "c", "parentId": "b"}, {"id": "d", "parentId": "c"}], "d")
Expected Output: ['r', 'a', 'b', 'c', 'd']
Explanation: A deep chain r->a->b->c->d returned root-first.
Hints
- Build a map id -> effective parent, normalizing both null and dangling parents to 'no parent' (None).
- Walk upward from the target collecting ids until you hit a node with no parent, then reverse the collected list.
- Guard against cycles with a visited set so a malformed input can't loop forever; also return [] up front when the target isn't present.