Design 2D DP on a DAG
Company: Amazon
Role: Software Engineer
Category: Coding & Algorithms
Difficulty: Medium
Interview Round: Technical Screen
Quick Answer: Design 2D DP on a DAG evaluates algorithm design, data structures, correctness, complexity, edge cases, and implementation details in a realistic interview setting. A strong answer states assumptions, handles edge cases, explains trade-offs, and shows how to validate the result clearly.
Constraints
- 1 <= n <= 10^4
- 0 <= L <= 200
- 0 <= edges.length <= 5 * 10^4
- Each edge is [u, v] with 0 <= u, v < n; the graph is acyclic.
- 0 <= source < n
- Path counts fit in a signed 64-bit integer for the given inputs.
Examples
Input: (4, [[0,1],[0,2],[1,3],[2,3]], 0, 2)
Expected Output: [[1, 0, 0], [0, 1, 0], [0, 1, 0], [0, 0, 2]]
Explanation: Diamond DAG. Node 3 has two distinct 2-edge paths from 0 (0->1->3 and 0->2->3), so dp[3][2]=2. Nodes 1 and 2 are each reached by one 1-edge path.
Input: (1, [], 0, 0)
Expected Output: [[1]]
Explanation: Base case: the only path from source 0 to itself using exactly 0 edges is the empty path, so dp[0][0]=1.
Input: (3, [[0,1],[1,2],[0,2]], 0, 3)
Expected Output: [[1, 0, 0, 0], [0, 1, 0, 0], [0, 1, 1, 0]]
Explanation: Node 2 is reachable both directly (0->2, 1 edge) and via node 1 (0->1->2, 2 edges), so dp[2][1]=1 and dp[2][2]=1.
Input: (5, [[0,1],[1,2],[2,3],[3,4]], 0, 4)
Expected Output: [[1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1]]
Explanation: A simple chain: the only way to reach node i is via the unique i-edge path, so dp[i][i]=1 along the diagonal.
Input: (3, [[0,1]], 0, 2)
Expected Output: [[1, 0, 0], [0, 1, 0], [0, 0, 0]]
Explanation: Node 2 is unreachable from source 0, so its entire row stays 0 — covering the disconnected/unreachable edge case.
Input: (2, [], 0, 1)
Expected Output: [[1, 0], [0, 0]]
Explanation: No edges: only dp[0][0]=1; node 1 is unreachable and there are no 1-edge paths from the source at all.
Hints
- Process nodes in topological order so dp[u][*] is fully computed before you push its contributions to successors.
- Base case is dp[source][0] = 1 (the zero-edge path from source to itself); every other entry starts at 0.
- Transition: for edge u -> v, every length-k path to u extends to a length-(k+1) path to v, so dp[v][k+1] += dp[u][k] for 0 <= k < L.
- To save memory when you only need exactly-L paths to one target, keep just two layers (k and k+1) and roll them — O(N) instead of O(N*L).