Unique Paths II – Solution & Complexity
Solution Walkthrough
1. Set up the grid recurrence
- Let
ways[r][c]be the number of obstacle-free paths that reach cell(r, c). - You can only arrive from the cell above or the cell to the left, so
ways[r][c] = ways[r-1][c] + ways[r][c-1]. - An obstacle cell is unreachable, so its count is
0.
2. Fill a full 2D table
- Seed the start cell with
1unless it is an obstacle. - Sweep every cell in row-major order, zeroing obstacles and summing the reachable neighbors otherwise.
- The answer sits in the bottom-right cell.
3. Reuse a single rolling row
- When you process row by row,
dp[c]already holds the count from the row above, anddp[c-1]holds the freshly updated count from the left. - So a single 1D array of width
colsis enough:dp[c] += dp[c-1]for open cells,dp[c] = 0for obstacles.
4. Optimal O(n)-space sweep
- Initialize
dp[0]from the start cell, then sweep every row updating the same array in place. - Obstacles reset their column to
0; open cells add the value to their left. The final answer isdp[cols-1].
5. Dry run
Trace [[0,0,0],[0,1,0],[0,0,0]] with the rolling row.
| after row | dp |
|---|---|
row 0 [0,0,0] | [1,1,1] |
row 1 [0,1,0] | [1,0,1] |
row 2 [0,0,0] | [1,1,2] |
The answer is dp[2] = 2.
6. Common mistakes and follow-ups
- Seeding the start cell as
1even when it is an obstacle, which over-counts every path. - Forgetting that an obstacle must reset its cell to
0in the rolling array, not just skip it. - Assuming a blocked destination still has paths.
- Follow-up: how would diagonal moves or a cost per cell change the recurrence?
7. Edge cases to test mentally
- A single free cell has exactly one path; a single blocked cell has none.
- A fully blocked row or column cuts every path to
0. - A blocked start or destination yields
0regardless of the rest of the grid.
8. Final full solution and complexity
A row-by-row sweep over one rolling DP row counts obstacle-free paths. Time is O(m*n) and extra space is O(n).