There is a robot on an m x n
grid. The robot is initially located at the top-left corner (i.e., grid[0][0]
). The robot tries to move to the bottom-right corner (i.e., grid[m - 1][n - 1]
). The robot can only move either down or right at any point in time. Given the two integers m
and n
, return the number of possible unique paths that the robot can take to reach the bottom-right corner. The test cases are generated so that the answer will be less than or equal to 2 * 10<sup>9</sup>
. For example, if m = 3
and n = 7
, the expected output is 28. Explain your approach, provide code, and analyze the time and space complexity. Also discuss edge cases and alternative solutions using combinatorics.
This problem asks us to find the number of unique paths a robot can take to reach the bottom-right corner of an m x n
grid, given that the robot can only move down or right.
A naive approach is to use recursion. We can define a recursive function that takes the current row and column as input. The base cases are:
Otherwise, we recursively call the function by moving down and moving right, and return the sum of the results.
def unique_paths_recursive(m, n):
def solve(row, col):
if row == m - 1 and col == n - 1:
return 1
if row >= m or col >= n:
return 0
return solve(row + 1, col) + solve(row, col + 1)
return solve(0, 0)
# Example usage:
m = 3
n = 7
result = unique_paths_recursive(m, n)
print(f"Number of unique paths for m={m}, n={n}: {result}") # Output: 28
This brute-force recursive solution has overlapping subproblems, leading to exponential time complexity. It will result in TLE (Time Limit Exceeded) for larger values of m
and n
.
We can optimize this using dynamic programming. We create a 2D array dp
of size m x n
, where dp[i][j]
stores the number of unique paths to reach cell (i, j)
. We initialize the first row and first column with 1 because there's only one way to reach any cell in the first row or first column.
Then, we iterate through the rest of the cells, and the number of unique paths to reach dp[i][j]
is the sum of the unique paths to reach dp[i-1][j]
(moving down) and dp[i][j-1]
(moving right).
def unique_paths_dp(m, n):
dp = [[0] * n for _ in range(m)]
# Initialize first row and first column to 1
for i in range(m):
dp[i][0] = 1
for j in range(n):
dp[0][j] = 1
# Calculate unique paths for the rest of the cells
for i in range(1, m):
for j in range(1, n):
dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
return dp[m - 1][n - 1]
# Example usage:
m = 3
n = 7
result = unique_paths_dp(m, n)
print(f"Number of unique paths for m={m}, n={n}: {result}") # Output: 28
The dynamic programming solution has a time complexity of O(m * n), where m
is the number of rows and n
is the number of columns in the grid. This is because we iterate through each cell in the m x n
grid once to calculate the number of unique paths.
The recursive solution will have exponential time complexity due to the overlapping subproblems and repeated calculations.
The dynamic programming solution has a space complexity of O(m * n) because we use a 2D array dp
of size m x n
to store the number of unique paths for each cell. We can further optimize this to O(n) by only storing the previous row to calculate number of paths.
The recursive solution has space complexity of O(m + n) due to the recursive call stack.
n-1
times).m-1
times).These edge cases are handled correctly by both the recursive and dynamic programming solutions.
This problem can also be solved using combinatorics. The robot needs to move a total of m + n - 2
steps, where m - 1
steps are down and n - 1
steps are right. The number of unique paths is equivalent to choosing m - 1
down steps from the total m + n - 2
steps, which can be calculated using the binomial coefficient:
C(m + n - 2, m - 1) = (m + n - 2)! / ((m - 1)! * (n - 1)!)
This can be implemented using factorials or by iteratively calculating the binomial coefficient to avoid large factorials.