Consider a maze mapped to a matrix with the upper left corner at coordinates (row, column) = (0, 0). You can only move towards the right or down from a cell. Determine the number of distinct paths through the maze. You must always start from the top-left position (0, 0) and end at the bottom-right (n-1, m-1).
For example, consider the following diagram where “1” indicates an open cell and “0” indicates a blocked cell. You can only travel through open cells, so no path can go through the cell (0, 2).
There are two possible paths from cell (0, 0) to cell (1, 3) in this matrix. Complete the function numberOfPaths, such that function returns the number of paths through the matrix, modulo (10^9 + 7).
Here are a couple of examples to get you started:
Example One
There are 10 possible paths from cell (0, 0) to cell (2, 3).
Example Two
There is one possible path from cell (0, 0) to cell (1, 1).
Notes:
Input Parameters: The function contains a single argument — a two-dimensional integer array called “matrix.”
Output: Return an integer — the number of possible paths from (0, 0) to (n-1, m-1).
Constraints:
Solution 1: Brute Force (brute_force_solution.java)
We have a matrix with n rows and m columns, where each cell, matrix[A][B], denotes whether it is accessible or not.
We will use recursion to solve this problem.
We know that the number of ways to reach a cell is the sum of the number of ways to reach the cell to its left and the number of ways to reach the cell above it. Therefore:
No. of ways to reach matrix[i][j] =
No. of ways to reach matrix[i-1][j] + No. of ways to reach matrix[i][j-1]
This is because we can only go right or downward from any cell.
Now, we start from a cell and perform recursion to find the number of ways to reach cell (n-1, m-1):
recur(matrix, n-1, m-1) = recur(matrix, n-2, m-1) + recur(matrix, n-1, m-2)
For each cell, we will check if it is accessible or not. If it is not, we simply return 0, as there is no way to reach it. The base condition would be that if cell (0,0) is accessible, then the number of ways to reach it is 1.
Time Complexity:
O(2^(rows+columns))
In each recursion step, we will either reduce n by 1 or m by 1. Hence, the recurrence relation will be:
T(n + m) = T(n - 1 + m) + T(n + m - 1) + O(1)
T(n + m) = 2 * T(n - 1 + m) + O(1)
Therefore, it is O(2^(n+m)).
Auxiliary Space Used:
O(rows+columns)
We do not create any auxiliary array for the solution. We use recursion, which uses O(rows+columns) stack space as the maximum steps can be rows+columns at a time.
Space Complexity:
O(rows*columns)
Input takes O(rows*columns) space, the auxiliary space used is O(rows+columns), and the output takes O(1). Summing these up, we get O(rows*columns).
Solution 2: Optimal Solution Using Dynamic Programming (optimal_solution.java)
We have a matrix with n rows and m columns, where each cell, matrix[A][B], denotes whether it is accessible or not.
Solution 1 (recursive) was exponential. We are visiting multiple states over and over, and then recursing for them, which we can surely avoid. To avoid revisiting states that have already been visited, we can store them in a dp array, so that they can be accessed as and when needed. This approach is known as Dynamic Programming.
Here’s how we do it:
Time Complexity:
O(n*m), considering the number of rows is n and columns is m.
We traverse the entire array matrix once and simultaneously traverse the dp array to keep the number of ways to reach that cell from cell (0,0). So, we travel both arrays at most once, and hence, the time complexity is O(n*m).
Auxiliary Space Used:
O(n*m), considering the number of rows is n and columns is m.
We create a two-dimensional array dp of size n*m to store the number of paths from cell (0,0) to the current cell. Hence, the auxiliary space used is O(n*m).
Space Complexity:
O(n*m), considering the number of rows is n and columns is m.
Consider a maze mapped to a matrix with the upper left corner at coordinates (row, column) = (0, 0). You can only move towards the right or down from a cell. Determine the number of distinct paths through the maze. You must always start from the top-left position (0, 0) and end at the bottom-right (n-1, m-1).
For example, consider the following diagram where “1” indicates an open cell and “0” indicates a blocked cell. You can only travel through open cells, so no path can go through the cell (0, 2).
There are two possible paths from cell (0, 0) to cell (1, 3) in this matrix. Complete the function numberOfPaths, such that function returns the number of paths through the matrix, modulo (10^9 + 7).
Here are a couple of examples to get you started:
Example One
There are 10 possible paths from cell (0, 0) to cell (2, 3).
Example Two
There is one possible path from cell (0, 0) to cell (1, 1).
Notes:
Input Parameters: The function contains a single argument — a two-dimensional integer array called “matrix.”
Output: Return an integer — the number of possible paths from (0, 0) to (n-1, m-1).
Constraints:
Solution 1: Brute Force (brute_force_solution.java)
We have a matrix with n rows and m columns, where each cell, matrix[A][B], denotes whether it is accessible or not.
We will use recursion to solve this problem.
We know that the number of ways to reach a cell is the sum of the number of ways to reach the cell to its left and the number of ways to reach the cell above it. Therefore:
No. of ways to reach matrix[i][j] =
No. of ways to reach matrix[i-1][j] + No. of ways to reach matrix[i][j-1]
This is because we can only go right or downward from any cell.
Now, we start from a cell and perform recursion to find the number of ways to reach cell (n-1, m-1):
recur(matrix, n-1, m-1) = recur(matrix, n-2, m-1) + recur(matrix, n-1, m-2)
For each cell, we will check if it is accessible or not. If it is not, we simply return 0, as there is no way to reach it. The base condition would be that if cell (0,0) is accessible, then the number of ways to reach it is 1.
Time Complexity:
O(2^(rows+columns))
In each recursion step, we will either reduce n by 1 or m by 1. Hence, the recurrence relation will be:
T(n + m) = T(n - 1 + m) + T(n + m - 1) + O(1)
T(n + m) = 2 * T(n - 1 + m) + O(1)
Therefore, it is O(2^(n+m)).
Auxiliary Space Used:
O(rows+columns)
We do not create any auxiliary array for the solution. We use recursion, which uses O(rows+columns) stack space as the maximum steps can be rows+columns at a time.
Space Complexity:
O(rows*columns)
Input takes O(rows*columns) space, the auxiliary space used is O(rows+columns), and the output takes O(1). Summing these up, we get O(rows*columns).
Solution 2: Optimal Solution Using Dynamic Programming (optimal_solution.java)
We have a matrix with n rows and m columns, where each cell, matrix[A][B], denotes whether it is accessible or not.
Solution 1 (recursive) was exponential. We are visiting multiple states over and over, and then recursing for them, which we can surely avoid. To avoid revisiting states that have already been visited, we can store them in a dp array, so that they can be accessed as and when needed. This approach is known as Dynamic Programming.
Here’s how we do it:
Time Complexity:
O(n*m), considering the number of rows is n and columns is m.
We traverse the entire array matrix once and simultaneously traverse the dp array to keep the number of ways to reach that cell from cell (0,0). So, we travel both arrays at most once, and hence, the time complexity is O(n*m).
Auxiliary Space Used:
O(n*m), considering the number of rows is n and columns is m.
We create a two-dimensional array dp of size n*m to store the number of paths from cell (0,0) to the current cell. Hence, the auxiliary space used is O(n*m).
Space Complexity:
O(n*m), considering the number of rows is n and columns is m.
Attend our free webinar to amp up your career and get the salary you deserve.