Refactor a Correct but Quadratic C++ Routine Under a Microsecond Budget
CitadelSoftware Engineer · Online AssessmentLast updated
Optimize an inefficient, quadratic tree-resolution routine into a linear-time, cache-friendly implementation suitable for ultra-low-latency execution.
Problem Statement
You are given a list of tree nodes representing a distributed execution tree. Each node is represented as a tuple (node_id, parent_id, weight):
node_id: A unique 32-bit signed integer identifier.parent_id: Thenode_idof the node's parent, or-1if this node is the root.weight: A 32-bit signed integer representing the processing cost of this node.
In the legacy production system, a naive routine traversed upwards from every leaf using linear scans (std::find_if) across an unsorted vector to verify parents, find the root, and compute path metrics. This caused O(N^2) runtime and unacceptable latency spikes.
Refactor this routine into an optimal linear-time O(N) solution that:
- Identifies the
root_idof the tree. - Computes the maximum weight path from the root to any leaf node (sum of node weights inclusive of root and leaf).
- Computes the maximum tree depth (number of edges from the root to the deepest leaf).
Your solution must execute within a strict latency budget, avoiding redundant allocations and excessive pointer chasing.
Function Signature
def analyze_execution_tree(nodes: list[tuple[int, int, int]]) -> tuple[int, int, int]:
"""
Returns:
(root_id, max_path_weight, max_depth)
"""
pass
Input & Output Format
- Input: A list of tuples
nodes, where each element is(node_id, parent_id, weight). - Output: A tuple of three integers:
(root_id, max_path_weight, max_depth).
Constraints
1 <= len(nodes) <= 100,000-2^31 <= node_id, parent_id <= 2^31 - 1-10^6 <= weight <= 10^6- Exactly one node will have
parent_id == -1. - The input is guaranteed to form a valid, single connected tree without cycles.
- Time Complexity requirement:
O(N) - Space Complexity requirement:
O(N)auxiliary space
Examples
Example 1
Input: nodes = [
(10, -1, 5),
(20, 10, 3),
(30, 10, 8),
(40, 20, 7)
]
Output: (10, 15, 2)
Explanation:
- Root is node
10(parent_id = -1). - Paths from root to leaves:
10 -> 30: weight =5 + 8 = 13, depth =1edge.10 -> 20 -> 40: weight =5 + 3 + 7 = 15, depth =2edges.
- Maximum path weight is
15, maximum depth is2.
Example 2
Input: nodes = [
(5, -1, -10)
]
Output: (5, -10, 0)
Explanation: Single node is the root. Path weight is -10, depth is 0.
Hints
Hint 1
Identify the root node in a single O(N) pass by inspecting which node has parent_id == -1, while simultaneously constructing an adjacency list.
Hint 2
Instead of repeated top-down or bottom-up linear scans, use a single depth-first search (DFS) or topological traversal starting from the root to compute both path weights and tree depths simultaneously.
Hint 3
For low-latency execution in systems like C++, pre-reserve capacity for hash maps or use flat arrays if IDs can be remapped to dense indices [0, N-1] to minimize heap allocations and cache misses.
Follow-up questions
- How would you design a differential fuzzing harness to prove bit-exact equivalence between the legacy quadratic routine and the optimized linear routine?
- If node IDs are non-contiguous and sparse, how could you avoid hash table lookup overhead entirely during the tree traversal phase?
- How would you prevent a call-stack overflow during DFS if the tree degrades into a linked list of 100,000 nodes?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.