Unique Paths in Grid DP in DSA Rust - Time & Space Complexity
We want to understand how the time needed to find unique paths in a grid grows as the grid size increases.
How does the number of steps change when the grid gets bigger?
Analyze the time complexity of the following code snippet.
fn unique_paths(m: usize, n: usize) -> usize {
let mut dp = vec![vec![1; n]; m];
for i in 1..m {
for j in 1..n {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
dp[m - 1][n - 1]
}
This code calculates the number of unique paths from the top-left to the bottom-right of an m by n grid using dynamic programming.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Nested loops filling the dp table.
- How many times: The inner loop runs (n-1) times for each of the (m-1) outer loop iterations.
As the grid size grows, the number of steps grows roughly with the product of rows and columns.
| Input Size (m x n) | Approx. Operations |
|---|---|
| 10 x 10 | 81 (9*9) |
| 100 x 100 | 9,801 (99*99) |
| 1000 x 1000 | 998,001 (999*999) |
Pattern observation: Doubling the grid size roughly quadruples the number of operations because both dimensions multiply.
Time Complexity: O(m * n)
This means the time needed grows proportionally with the total number of cells in the grid.
[X] Wrong: "The time grows exponentially because there are many paths."
[OK] Correct: The dynamic programming approach avoids repeated work by storing results, so it only visits each cell once.
Understanding this time complexity shows you can analyze how dynamic programming improves efficiency by avoiding repeated calculations.
"What if we used recursion without memoization? How would the time complexity change?"
Practice
Unique Paths means:Solution
Step 1: Understand the problem goal
The problem asks for counting all possible paths from the top-left corner to the bottom-right corner of a grid.Step 2: Identify allowed moves
Only moves to the right or down are allowed, so paths are sequences of these moves.Final Answer:
The number of ways to move from the top-left to bottom-right corner of a grid using only right and down moves -> Option AQuick Check:
Unique Paths = Count of right/down move sequences [OK]
- Thinking about shortest path length instead of count
- Including diagonal or left moves
- Confusing with maximum sum path
dp of size m x n with all values set to 1?Solution
Step 1: Understand vector dimensions
We want a vector withmrows andncolumns, so outer vector length ism, inner vector length isn.Step 2: Check initialization values
All values should be 1, so inner vector isvec![1; n], repeatedmtimes.Final Answer:
let dp = vec![vec![1; n]; m]; -> Option DQuick Check:
Outer length = m, inner length = n, all 1s [OK]
- Swapping m and n in vector sizes
- Initializing with zeros instead of ones
- Using incorrect vector syntax
m = 3 and n = 3?fn unique_paths(m: usize, n: usize) -> usize {
let mut dp = vec![vec![1; n]; m];
for i in 1..m {
for j in 1..n {
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
dp[m-1][n-1]
}
fn main() {
println!("{}", unique_paths(3, 3));
}Solution
Step 1: Initialize dp with 1s
dp is a 3x3 grid with all 1s initially.Step 2: Fill dp using formula dp[i][j] = dp[i-1][j] + dp[i][j-1]
Calculate dp values row by row: - dp[1][1] = dp[0][1] + dp[1][0] = 1 + 1 = 2 - dp[1][2] = dp[0][2] + dp[1][1] = 1 + 2 = 3 - dp[2][1] = dp[1][1] + dp[2][0] = 2 + 1 = 3 - dp[2][2] = dp[1][2] + dp[2][1] = 3 + 3 = 6Final Answer:
6 -> Option BQuick Check:
Unique paths in 3x3 grid = 6 [OK]
- Not initializing first row and column with 1
- Adding dp[i][j-1] and dp[i-1][j] incorrectly
- Returning wrong dp cell
fn unique_paths(m: usize, n: usize) -> usize {
let mut dp = vec![vec![0; n]; m];
for i in 0..m {
for j in 0..n {
if i == 0 || j == 0 {
dp[i][j] = 1;
} else {
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
}
dp[m][n]
}Solution
Step 1: Check dp indexing at return
dp indices go from 0 to m-1 and 0 to n-1, so dp[m][n] is out of bounds and causes error.Step 2: Fix return statement
Return dp[m-1][n-1] to get bottom-right cell value.Final Answer:
Change return to dp[m-1][n-1] -> Option AQuick Check:
Return dp[m-1][n-1] to avoid index error [OK]
- Returning dp[m][n] causing runtime panic
- Not initializing first row and column
- Starting loops incorrectly
Choose the correct approach:
Solution
Step 1: Initialize dp considering obstacles
Set dp cells to 0 if obstacle present; dp[0][0] = 1 only if start is free.Step 2: Update dp values skipping obstacles
For each cell, if obstacle, dp[i][j] = 0; else dp[i][j] = dp[i-1][j] + dp[i][j-1]. This counts only valid paths.Final Answer:
Initialize dp with zeros; set dp[0][0] = 1 if no obstacle; for each cell, if obstacle, dp[i][j] = 0 else dp[i][j] = dp[i-1][j] + dp[i][j-1] -> Option CQuick Check:
Obstacles block paths by setting dp cells to zero [OK]
- Ignoring obstacles in dp calculation
- Subtracting paths after counting all
- Using recursion without memoization causing inefficiency
Ready to prove it?
Pass the test and this pattern moves unknown
