Unique Paths in Grid DP in DSA C - Time & Space Complexity
We want to know how the time needed to find unique paths in a grid changes as the grid size grows.
How does the number of steps grow when the grid gets bigger?
Analyze the time complexity of the following code snippet.
int uniquePaths(int m, int n) {
int dp[m][n];
for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int j = 0; j < n; j++) dp[0][j] = 1;
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
return 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: The nested loops that fill the dp table.
- How many times: The inner loop runs (m-1) * (n-1) times, covering almost all cells except the first row and column.
As the grid size grows, the number of operations grows roughly with the number of cells in the grid.
| 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: The operations grow roughly by the product of m and n, so doubling both dimensions roughly quadruples the work.
Time Complexity: O(m * n)
This means the time needed grows proportionally to 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, making the time grow linearly with the grid size.
Understanding this time complexity helps you explain how dynamic programming improves efficiency by avoiding repeated calculations, a key skill in many coding challenges.
"What if we used recursion without memoization? How would the time complexity change?"
Practice
Solution
Step 1: Understand the problem goal
The problem asks for counting all possible paths from the start (top-left) to the end (bottom-right) moving only right or down.Step 2: Clarify movement constraints
Only moves allowed are right or down, no diagonal or backward moves.Final Answer:
The number of different ways to move from the top-left to the bottom-right corner of a grid using only right and down moves. -> Option DQuick Check:
Unique paths = count of right/down moves combinations [OK]
- Thinking diagonal moves are allowed
- Confusing path count with shortest path
- Counting obstacles instead of paths
Solution
Step 1: Understand array initialization in C
Arrays cannot be assigned directly after declaration; memset is used to set all bytes to zero.Step 2: Check each option
int dp[m][n] = {0}; tries to initialize with {0} which works only for static arrays, not variable length arrays. int dp[m][n]; memset(dp, 0, sizeof(dp)); uses memset correctly. int dp[m][n]; dp = 0; tries invalid assignment. int dp[m][n] = NULL; assigns NULL which is invalid for arrays.Final Answer:
int dp[m][n]; memset(dp, 0, sizeof(dp)); -> Option CQuick Check:
Use memset to zero initialize arrays in C [OK]
- Trying to assign 0 directly to array
- Using NULL for arrays
- Assuming {0} works for variable length arrays
int uniquePaths(int m, int n) {
int dp[m][n];
memset(dp, 0, sizeof(dp));
for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int j = 0; j < n; j++) dp[0][j] = 1;
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
return dp[m-1][n-1];
}
printf("%d", uniquePaths(3, 3));Solution
Step 1: Initialize first row and column
First row and column are set to 1 because only one way to reach cells in first row (all right moves) or first column (all down moves).Step 2: Fill dp table using sum of top and left cells
For each cell dp[i][j], value = dp[i-1][j] + dp[i][j-1]. For 3x3 grid, dp[2][2] = 6.Final Answer:
6 -> Option BQuick Check:
Unique paths in 3x3 grid = 6 [OK]
- Not initializing first row and column to 1
- Adding instead of summing dp[i-1][j] and dp[i][j-1]
- Returning wrong dp cell
int uniquePaths(int m, int n) {
int dp[m][n];
memset(dp, 0, sizeof(dp));
for (int i = 0; i <= m; i++) dp[i][0] = 1;
for (int j = 0; j <= n; j++) dp[0][j] = 1;
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
return dp[m-1][n-1];
}Solution
Step 1: Check loop bounds for initialization
Loops use <= m and <= n which causes index to go out of bounds since valid indices are 0 to m-1 and 0 to n-1.Step 2: Identify correct loop bounds
Loops should use < m and < n to avoid accessing invalid indices.Final Answer:
The loops initializing dp go out of bounds causing runtime error. -> Option AQuick Check:
Array indices must be within 0 to size-1 [OK]
- Using <= instead of < in loops
- Ignoring array bounds causing crashes
- Incorrect initialization of dp array
0 0 0 0 0 1 0 0 0 0 1 0 0 0 0 0
Solution
Step 1: Mark blocked cells in dp as zero
If a cell is blocked (value 1), no paths can go through it, so dp[i][j] = 0.Step 2: Calculate dp for free cells
For free cells (value 0), dp[i][j] = dp[i-1][j] + dp[i][j-1], summing paths from top and left.Final Answer:
Set dp[i][j] = 0 if cell is blocked; else dp[i][j] = dp[i-1][j] + dp[i][j-1]. -> Option AQuick Check:
Blocked cells have zero paths [OK]
- Ignoring obstacles in path count
- Assigning 1 to blocked cells
- Using diagonal moves to avoid obstacles
Ready to prove it?
Pass the test and this pattern moves unknown
