![]() |
VOOZH | about |
Given a matrix mat[][] where each cell contains a certain number of coins, and an integer k, count the total number of distinct paths from the top-left cell to the bottom-right cell such that the sum of coins collected along the path is exactly k.
From any cell (i, j), we can move either downward (i + 1, j) or rightward (i, j + 1).
Example:
Input: k = 12, mat[][] = [[1, 2, 3],
[4, 6, 5],
[3, 2, 1]]
Output: 2
Explanation: There are two paths with 12 coins
1 -> 2 -> 6 -> 2 -> 1
1 -> 2 -> 3 -> 5 -> 1Input: k = 16, mat[][] = [[1, 2, 3],
[4, 6, 5],
[9, 8, 7]]
Output: 0
Explanation: There are no possible paths that lead to sum=16
Table of Content
The idea is to use recursion because we need to explore all possible paths from the top-left cell of the matrix to the bottom-right cell.
At each step, we can move:
- Downward - from cell (i, j) to (i + 1, j)
- Rightward - from cell (i, j) to (i, j + 1)
As we move, we keep adding the number of coins in the current cell to our running total. Whenever we reach the bottom-right cell, we check whether this total sum is exactly equal to k. If it matches k, we count this path as a valid path. If not, we simply return without counting it.
2
In the recursive approach, there are many overlapping subproblems that get solved repeatedly, which increases the time complexity.
To handle this issue, we use memoization.
We create a 3D DP array memo[n][m][k+1], because in the recursive function there are three parameters that keep changing:
- i: current row index
- j: current column index
- k: remaining sum
So, memo[i][j][k] stores the number of valid paths starting from cell (i, j) when the remaining sum is k.
Whenever we encounter the same subproblem again, we first check in the memo table whether it has already been solved. If it has, we directly return the stored result instead of recomputing it.
2
In this approach, instead of using recursion, we use bottom-up to build the solution iteratively.
We create a 3D DP array dp[n][m][k+1], where each entry dp[i][j][sum] represents the number of ways to reach cell (i, j) with a total sum of coins equal to sum.
We start from the top-left cell as our base case since it’s the starting point. So, if mat[0][0] ≤ k, we set dp[0][0][mat[0][0]] = 1, meaning there is exactly one valid way to reach (0, 0) with the sum equal to the value of that cell; otherwise, it’s not valid since the sum already exceeds k.
To fill the rest of the table, we use the relation:
dp[i][j][sum] = dp[i-1][j][sum - mat[i][j]] + dp[i][j-1][sum - mat[i][j]].
This means that to reach cell (i, j) with a total sum sum, we can either come from the top cell (i-1, j) or from the left cell (i, j-1) with the remaining sum sum - mat[i][j].
We then iterate through all cells (i, j) and all possible sums from 0 to k to fill the DP table.
2
In the previous approach, we used a 3D DP table dp[n][m][k+1]. But if we observe carefully, to calculate the value for the current row, we only need the values from the previous row and the current row itself.
So, instead of keeping the entire 3D table, we can store only two 2D arrays:
- prev[m][k+1] - represents results of the previous row
- curr[m][k+1] - represents results for the current row being calculated
After finishing one row, we simply copy curr to prev and reuse the same arrays for the next iteration.
2