Professional Documents
Culture Documents
Interview Question
David Wahler (dwahler@)
● ~8 years interviewing
● https://wiki.indeed.com/display/eng/Minimum+cost+in+a+tree
The Pitch and Setup
Setup
Problem statement:
Example includes:
● nodes with 0, 1, 2 and 3 children
● paths of different lengths
● edges with cost zero
● optimal leaf is neither first nor last
(when using DFS or BFS)
Setup
class Edge {
int cost; // ≥ 0
Node target; // non-null
}
struct Edge {
int cost; // ≥ 0
Node* target; // non-null
};
class Edge:
cost = … # type is int, ≥ 0
target = … # type is Node, not None
def minCostLeaf(root):
# …
return leaf_node
Common questions
Questions (1/3)
- Q: How big is the tree?
A: The tree fits in memory, and the depth is reasonably small (a few
hundred or so)
- (Bonus: the linear-time solution to the DAG extension is essentially equivalent to the Viterbi
algorithm, which is used to efficiently decode the error-correcting codes used in WiFi, LTE, etc.)
Brainstorming
Solutions
Key insights
● Recursive DFS
● Iterative BFS
☺ ● A* (requires extra
information that we ☹
● Dijkstra’s algorithm don’t have)
Naive solution (Recursive DFS, top-down)
● Dijkstra’s algorithm: visit nodes in order of cost, stopping at the first leaf
● Does a better job of pruning, but has overhead of maintaining a priority
queue
Dijkstra’s algorithm
● At this point, I point out that the same Node/Edge data structures can be
used to represent other kind of graphs (if candidate hasn’t already said so)
● Extension: solve the same problem on a directed acyclic graph with a
single root.
○ i.e. nodes can have multiple parents, which means multiple paths from the root
○ “Find the leaf node which has the shortest path that connects it to the root”
● Depending on time available, candidates typically don’t write code for a
complete solution to the extension
DAG extension
● The candidate’s tree solution will probably give the correct answer for a
DAG as well, but will be very expensive due to re-visiting nodes. Do they
realize this?
○ Worst-case is typically O(2V); many candidates hand-wave and suggest O(V2) or similar
● If not, draw example e.g. repeated diamonds
● Pruning helps a bit, but not in the worst case
DAG extension
● Incorrect solutions:
○ DFS, skipping already-visited nodes
○ BFS, skipping already-visited nodes (shorter paths may have more edges)
● Correct solutions:
○ Dijkstra’s, skipping already-expanded nodes
○ Dynamic programming:
■ Bottom-up DFS with memoization
■ Topological sort
Bottom-up DFS with memoization (1/2)
Result result;
if (current.children.isEmpty()) {
result = new Result(0, current);
} else {
// …
Bottom-up DFS with memoization (2/2)
} else {
Result best = null;
for (Edge e : current.children) {
Result candidate = dfs(e.target, memo);
candidate = new Result(candidate.cost + e.cost,
candidate.target);
if (best == null || candidate.cost < best.cost) {
best = candidate;
}
}
result = best;
}
memo.put(current, result);
return result;
}
Discussion points
Discussion points
● Test cases
○ Trivial tree (root has no children)
○ Large costs (integer overflow)
○ Tree with large height (stack overflow)
○ Input constraint validation?
■ null pointers
■ negative costs
■ cycles
Discussion points
● Time complexity
○ Naive DFS/BFS is O(N) for a tree, O(V + E) for a DAG
○ With pruning, still O(N), but probably performs much better in practice
○ Dijkstra’s: O(N log N) for a tree, O(E log E) for a DAG
■ DAG complexity can be improved to O(E log V) with a custom priority queue
● Space complexity
○ DFS: O(depth)
■ Some candidates store costs in a map and don’t clean them up, which means space
is O(N)
○ BFS: O(width)
○ Dijkstra’s/memoization: O(N)
Common pitfalls (1/2)
● No
○ Unable to solve tree
● Weak No
○ Needs significant assistance to solve tree; no workable ideas for DAG
● Yes
○ Correct, efficient code for tree; at least one independent, non-trivial idea for DAG
● Strong Yes
○ Solves tree easily; discusses pros-and-cons of multiple approaches for DAG; no significant
implementation bugs (or finds/fixes them without help)
Conclusion
Pros
● Room to discuss multiple “optimal” solutions
○ including trading worst-case for average-case
● Good at testing ability to mentally model how code behaves
● Tests both analytical and implementation skills
Cons
● Solutions depend on a relatively small number of distinct insights
● Not good for phone screens
● Has been asked a lot over the years
Open Q & A