Number of paths with exactly k coins (original) (raw)

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 -> 1

**Input: 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

[Naive Approach] Using Recursion - O(2(m+n)) Time and O(m+n) Auxiliary Space

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:

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.

C++ `

//Driver Code Starts #include #include using namespace std; //Driver Code Ends

// Recursive function to count paths int pathCountRec(vector<vector>& mat, int i, int j, int k) { int n = mat.size(); int m = mat[0].size();

// Base conditions
if (i >= n || j >= m) return 0;

 // Sum exceeded then return
if (k < 0) return 0;            

// Reached destination cell
if (i == n - 1 && j == m - 1)
    return (k == mat[i][j]);     

// Move either right or down and reduce the required sum
return pathCountRec(mat, i + 1, j, k - mat[i][j]) +
       pathCountRec(mat, i, j + 1, k - mat[i][j]);

}

int numberOfPath(vector<vector>& mat, int k) { return pathCountRec(mat, 0, 0, k); }

//Driver Code Starts int main() { int k = 12; vector<vector> mat = { {1, 2, 3}, {4, 6, 5}, {3, 2, 1} };

cout << numberOfPath(mat, k);
return 0;

}

//Driver Code Ends

Java

//Driver Code Starts class GFG { //Driver Code Ends

// Recursive function to count paths 
static int pathCountRec(int[][] mat, int i, int j, int k) {
    int n = mat.length;
    int m = mat[0].length;

    // Base conditions
    if (i >= n || j >= m)
        return 0;

    // Sum exceeded then return
    if (k < 0)
        return 0;

    // Reached destination cell
    if (i == n - 1 && j == m - 1)
        return (k == mat[i][j]) ? 1 : 0;

    // Move either right or down and reduce the required sum
    return pathCountRec(mat, i + 1, j, k - mat[i][j]) +
           pathCountRec(mat, i, j + 1, k - mat[i][j]);
}

static int numberOfPath(int[][] mat, int k) {
    return pathCountRec(mat, 0, 0, k);
}

//Driver Code Starts public static void main(String[] args) { int k = 12; int[][] mat = { {1, 2, 3}, {4, 6, 5}, {3, 2, 1} };

    System.out.println(numberOfPath(mat, k));
}

}

//Driver Code Ends

Python

Recursive function to count paths

def pathCountRec(mat, i, j, k): n = len(mat) m = len(mat[0])

# Base conditions
if i >= n or j >= m:
    return 0

# Sum exceeded then return
if k < 0:
    return 0

# Reached destination cell
if i == n - 1 and j == m - 1:
    return 1 if k == mat[i][j] else 0

# Move either right or down and reduce the required sum
return (pathCountRec(mat, i + 1, j, k - mat[i][j]) +
        pathCountRec(mat, i, j + 1, k - mat[i][j]))

def numberOfPath(mat, k): return pathCountRec(mat, 0, 0, k)

if name == "main": #Driver Code Starts k = 12 mat = [ [1, 2, 3], [4, 6, 5], [3, 2, 1] ]

print(numberOfPath(mat, k))

#Driver Code Ends

C#

//Driver Code Starts using System;

class GFG { //Driver Code Ends

// Recursive function to count paths 
static int pathCountRec(int[,] mat, int i, int j, int k) {
    int n = mat.GetLength(0);
    int m = mat.GetLength(1);

    // Base conditions
    if (i >= n || j >= m)
        return 0;

    // Sum exceeded then return
    if (k < 0)
        return 0;

    // Reached destination cell
    if (i == n - 1 && j == m - 1)
        return (k == mat[i, j]) ? 1 : 0;

    // Move either right or down and reduce the required sum
    return pathCountRec(mat, i + 1, j, k - mat[i, j]) +
           pathCountRec(mat, i, j + 1, k - mat[i, j]);
}

static int numberOfPath(int[,] mat, int k) {
    return pathCountRec(mat, 0, 0, k);
}

//Driver Code Starts static void Main() { int k = 12; int[,] mat = { {1, 2, 3}, {4, 6, 5}, {3, 2, 1} };

    Console.WriteLine(numberOfPath(mat, k));
}

}

//Driver Code Ends

JavaScript

// Recursive function to count paths function pathCountRec(mat, i, j, k) { const n = mat.length; const m = mat[0].length;

// Base conditions
if (i >= n || j >= m) return 0;

// Sum exceeded then return
if (k < 0) return 0;

// Reached destination cell
if (i === n - 1 && j === m - 1)
    return (k === mat[i][j]) ? 1 : 0;

// Move either right or down and reduce the required sum
return pathCountRec(mat, i + 1, j, k - mat[i][j]) +
       pathCountRec(mat, i, j + 1, k - mat[i][j]);

}

function numberOfPath(mat, k) { return pathCountRec(mat, 0, 0, k); }

// Driver code //Driver Code Starts const k = 12; const mat = [ [1, 2, 3], [4, 6, 5], [3, 2, 1] ];

console.log(numberOfPath(mat, k));

//Driver Code Ends

`

[Better Approach 1] Using Top Down (Memoization) - O(m*n*k) Time and O(n*m*k) Space

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:

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.

C++ `

//Driver Code Starts #include #include using namespace std; //Driver Code Ends

// Recursive function with memoization int pathCountRec(vector<vector>& mat, int i, int j, int k, vector<vector<vector>>& dp) { int n = mat.size(); int m = mat[0].size();

if (i >= n || j >= m) return 0;

// Sum exceeded
if (k < 0) return 0;

if (i == n - 1 && j == m - 1)
    return (k == mat[i][j]);

// If already computed, return stored value
if (dp[i][j][k] != -1)
    return dp[i][j][k];

// Explore down and right moves
int down = pathCountRec(mat, i + 1, j, k - mat[i][j], dp);
int right = pathCountRec(mat, i, j + 1, k - mat[i][j], dp);

return dp[i][j][k] = down + right;

}

int numberOfPath(vector<vector>& mat, int k) { int n = mat.size(); int m = mat[0].size();

vector<vector<vector<int>>> dp(
    n, vector<vector<int>>(m, vector<int>(k + 1, -1))
);

return pathCountRec(mat, 0, 0, k, dp);

}

//Driver Code Starts int main() { int k = 12; vector<vector> mat = { {1, 2, 3}, {4, 6, 5}, {3, 2, 1} };

cout << numberOfPath(mat, k);
return 0;

}

//Driver Code Ends

Java

//Driver Code Starts import java.util.Arrays;

class GFG { //Driver Code Ends

// Recursive function with memoization
static int pathCountRec(int[][] mat, int i, int j, int k, int[][][] dp) {
    int n = mat.length;
    int m = mat[0].length;

    if (i >= n || j >= m)
        return 0;

    // Sum exceeded
    if (k < 0)
        return 0;

    if (i == n - 1 && j == m - 1)
        return (k == mat[i][j]) ? 1 : 0;

    // If already computed, return stored value
    if (dp[i][j][k] != -1)
        return dp[i][j][k];

    // Explore down and right moves
    int down = pathCountRec(mat, i + 1, j, k - mat[i][j], dp);
    int right = pathCountRec(mat, i, j + 1, k - mat[i][j], dp);

    return dp[i][j][k] = down + right;
}

static int numberOfPath(int[][] mat, int k) {
    int n = mat.length;
    int m = mat[0].length;

    int[][][] dp = new int[n][m][k + 1];
    for (int[][] arr2D : dp)
        for (int[] arr1D : arr2D)
            Arrays.fill(arr1D, -1);

    return pathCountRec(mat, 0, 0, k, dp);
}

//Driver Code Starts public static void main(String[] args) { int k = 12; int[][] mat = { {1, 2, 3}, {4, 6, 5}, {3, 2, 1} };

    System.out.println(numberOfPath(mat, k));
}

}

//Driver Code Ends

Python

Recursive function with memoization

def pathCountRec(mat, i, j, k, dp): n = len(mat) m = len(mat[0])

if i >= n or j >= m:
    return 0

# Sum exceeded
if k < 0:
    return 0

if i == n - 1 and j == m - 1:
    return 1 if k == mat[i][j] else 0

# If already computed, return stored value
if dp[i][j][k] != -1:
    return dp[i][j][k]

# Explore down and right moves
down = pathCountRec(mat, i + 1, j, k - mat[i][j], dp)
right = pathCountRec(mat, i, j + 1, k - mat[i][j], dp)

dp[i][j][k] = down + right
return dp[i][j][k]

def numberOfPath(mat, k): n = len(mat) m = len(mat[0])

dp = [[[-1 for _ in range(k + 1)] for _ in range(m)] for _ in range(n)]

return pathCountRec(mat, 0, 0, k, dp)

#Driver Code Starts if name == "main": k = 12 mat = [ [1, 2, 3], [4, 6, 5], [3, 2, 1] ]

print(numberOfPath(mat, k))

#Driver Code Ends

C#

//Driver Code Starts using System;

class GFG { //Driver Code Ends

// Recursive function with memoization
static int pathCountRec(int[,] mat, int i, int j, int k, int[,,] dp) {
    int n = mat.GetLength(0);
    int m = mat.GetLength(1);

    if (i >= n || j >= m)
        return 0;

    // Sum exceeded
    if (k < 0)
        return 0;

    if (i == n - 1 && j == m - 1)
        return (k == mat[i, j]) ? 1 : 0;

    // If already computed, return stored value
    if (dp[i, j, k] != -1)
        return dp[i, j, k];

    // Explore down and right moves
    int down = pathCountRec(mat, i + 1, j, k - mat[i, j], dp);
    int right = pathCountRec(mat, i, j + 1, k - mat[i, j], dp);

    return dp[i, j, k] = down + right;
}

static int numberOfPath(int[,] mat, int k) {
    int n = mat.GetLength(0);
    int m = mat.GetLength(1);

    int[,,] dp = new int[n, m, k + 1];

    for (int x = 0; x < n; x++)
        for (int y = 0; y < m; y++)
            for (int z = 0; z <= k; z++)
                dp[x, y, z] = -1;

    return pathCountRec(mat, 0, 0, k, dp);
}

//Driver Code Starts static void Main() { int k = 12; int[,] mat = { {1, 2, 3}, {4, 6, 5}, {3, 2, 1} };

    Console.WriteLine(numberOfPath(mat, k));
}

}

//Driver Code Ends

JavaScript

// Recursive function with memoization function pathCountRec(mat, i, j, k, dp) { const n = mat.length; const m = mat[0].length;

if (i >= n || j >= m)
    return 0;

// Sum exceeded
if (k < 0)
    return 0;

if (i === n - 1 && j === m - 1)
    return (k === mat[i][j]) ? 1 : 0;

// If already computed, return stored value
if (dp[i][j][k] !== -1)
    return dp[i][j][k];

// Explore down and right moves
const down = pathCountRec(mat, i + 1, j, k - mat[i][j], dp);
const right = pathCountRec(mat, i, j + 1, k - mat[i][j], dp);

dp[i][j][k] = down + right;
return dp[i][j][k];

}

function numberOfPath(mat, k) { const n = mat.length; const m = mat[0].length;

const dp = Array.from({ length: n }, () =>
    Array.from({ length: m }, () => Array(k + 1).fill(-1))
);

return pathCountRec(mat, 0, 0, k, dp);

}

// Driver code //Driver Code Starts const k = 12; const mat = [ [1, 2, 3], [4, 6, 5], [3, 2, 1] ];

console.log(numberOfPath(mat, k));

//Driver Code Ends

`

[Better Approach 2] Using Bottom Up (Tabulation) - O(n*m*k) Time and O(n*m*k) Space

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.

C++ `

//Driver Code Starts #include #include using namespace std; //Driver Code Ends

int numberOfPath(vector<vector>& mat, int k) { int n = mat.size(), m = mat[0].size(); vector<vector<vector>> dp(n, vector<vector>(m, vector(k + 1, 0)));

// Base case
if (mat[0][0] <= k) 
dp[0][0][mat[0][0]] = 1;

// Build table iteratively 
for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
        for (int sum = 0; sum <= k; sum++) {
            if (sum - mat[i][j] >= 0) {
                
                // from top
                if (i > 0) dp[i][j][sum] += dp[i - 1][j][sum - mat[i][j]]; 
                
                 // from left
                if (j > 0) dp[i][j][sum] += dp[i][j - 1][sum - mat[i][j]];
                
            }
        }
    }
}

//total ways to reach bottom-right with sum = k
return dp[n - 1][m - 1][k];

}

//Driver Code Starts int main() { int k = 12; vector<vector> mat = { {1, 2, 3}, {4, 6, 5}, {3, 2, 1} }; cout << numberOfPath(mat, k); return 0; }

//Driver Code Ends

Java

//Driver Code Starts import java.util.Arrays;

class GFG { //Driver Code Ends

static int numberOfPath(int[][] mat, int k) {
    int n = mat.length, m = mat[0].length;
    int[][][] dp = new int[n][m][k + 1];

    // Base case
    if (mat[0][0] <= k)
        dp[0][0][mat[0][0]] = 1;

    // Build table iteratively 
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            for (int sum = 0; sum <= k; sum++) {
                if (sum - mat[i][j] >= 0) {
                   
                    // from top
                    if (i > 0)
                        dp[i][j][sum] += dp[i - 1][j][sum - mat[i][j]];
                   
                    // from left
                    if (j > 0)
                        dp[i][j][sum] += dp[i][j - 1][sum - mat[i][j]];
                }
            }
        }
    }

    // total ways to reach bottom-right with sum = k
    return dp[n - 1][m - 1][k];
}

//Driver Code Starts public static void main(String[] args) { int k = 12; int[][] mat = { {1, 2, 3}, {4, 6, 5}, {3, 2, 1} };

    System.out.println(numberOfPath(mat, k));
}

}

//Driver Code Ends

Python

def numberOfPath(mat, k): n = len(mat) m = len(mat[0]) dp = [[[0 for _ in range(k + 1)] for _ in range(m)] for _ in range(n)]

# Base case
if mat[0][0] <= k:
    dp[0][0][mat[0][0]] = 1

# Build table iteratively 
for i in range(n):
    for j in range(m):
        for sum in range(k + 1):
            if sum - mat[i][j] >= 0:
              
                # from top
                if i > 0:
                    dp[i][j][sum] += dp[i - 1][j][sum - mat[i][j]]
              
                # from left
                if j > 0:
                    dp[i][j][sum] += dp[i][j - 1][sum - mat[i][j]]

# total ways to reach bottom-right with sum = k
return dp[n - 1][m - 1][k]

#Driver Code Starts if name == "main": k = 12 mat = [ [1, 2, 3], [4, 6, 5], [3, 2, 1] ] print(numberOfPath(mat, k))

#Driver Code Ends

C#

//Driver Code Starts using System;

class GFG { //Driver Code Ends

static int numberOfPath(int[,] mat, int k) {
    int n = mat.GetLength(0), m = mat.GetLength(1);
    int[,,] dp = new int[n, m, k + 1];

    // Base case
    if (mat[0, 0] <= k)
        dp[0, 0, mat[0, 0]] = 1;

    // Build table iteratively 
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            for (int sum = 0; sum <= k; sum++) {
                if (sum - mat[i, j] >= 0) {
                    
                    // from top
                    if (i > 0)
                        dp[i, j, sum] += dp[i - 1, j, sum - mat[i, j]];
                 
                    // from left
                    if (j > 0)
                        dp[i, j, sum] += dp[i, j - 1, sum - mat[i, j]];
                }
            }
        }
    }

    // total ways to reach bottom-right with sum = k
    return dp[n - 1, m - 1, k];
}

//Driver Code Starts static void Main() { int k = 12; int[,] mat = { {1, 2, 3}, {4, 6, 5}, {3, 2, 1} };

    Console.WriteLine(numberOfPath(mat, k));
}

}

//Driver Code Ends

JavaScript

function numberOfPath(mat, k) { const n = mat.length; const m = mat[0].length;

// create 3D dp array
const dp = Array.from({ length: n }, () =>
    Array.from({ length: m }, () => Array(k + 1).fill(0))
);

// Base case
if (mat[0][0] <= k)
    dp[0][0][mat[0][0]] = 1;

// Build table iteratively 
for (let i = 0; i < n; i++) {
    for (let j = 0; j < m; j++) {
        for (let sum = 0; sum <= k; sum++) {
            if (sum - mat[i][j] >= 0) {
               
                // from top
                if (i > 0)
                    dp[i][j][sum] += dp[i - 1][j][sum - mat[i][j]];
               
                // from left
                if (j > 0)
                    dp[i][j][sum] += dp[i][j - 1][sum - mat[i][j]];
            }
        }
    }
}

// total ways to reach bottom-right with sum = k
return dp[n - 1][m - 1][k];

}

// Driver Code //Driver Code Starts const k = 12; const mat = [ [1, 2, 3], [4, 6, 5], [3, 2, 1] ];

console.log(numberOfPath(mat, k));

//Driver Code Ends

`

[Expected Approach] Using Space Optimization - O(n*m*k) Time and O(m*k) Space

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:

After finishing one row, we simply copy curr to prev and reuse the same arrays for the next iteration.

C++ `

//Driver Code Starts #include #include using namespace std; //Driver Code Ends

int numberOfPath(vector<vector>& mat, int k) { int n = mat.size(), m = mat[0].size();

 // Use only two 2D arrays for space optimization
vector<vector<int>> prev(m, vector<int>(k + 1, 0));
vector<vector<int>> curr(m, vector<int>(k + 1, 0));

// Build DP table iteratively
for (int i = 0; i < n; i++) {
    for (int j = 0; j < m; j++) {
        for (int sum = 0; sum <= k; sum++) {
            
            // Base case
            if (i == 0 && j == 0) {
                
                // Only one way if sum matches cell value
                curr[j][sum] = (sum == mat[0][0]);
                continue;
            }

            curr[j][sum] = 0;

            if (sum - mat[i][j] >= 0) {
                
                // from top
                if (i > 0) curr[j][sum] += prev[j][sum - mat[i][j]];
               
                // from left
                if (j > 0) curr[j][sum] += curr[j - 1][sum - mat[i][j]];
            }
        }
    }
    
    // Move current row to previous row
    prev = curr;
}

// Total ways to reach bottom-right with sum = k
return prev[m - 1][k];

}

//Driver Code Starts int main() { int k = 12; vector<vector> mat = { {1, 2, 3}, {4, 6, 5}, {3, 2, 1} };

cout << numberOfPath(mat, k);
return 0;

}

//Driver Code Ends

Java

//Driver Code Starts import java.util.Arrays;

class GFG { //Driver Code Ends

static int numberOfPath(int[][] mat, int k) {
    int n = mat.length, m = mat[0].length;

    // Use only two 2D arrays for space optimization
    int[][] prev = new int[m][k + 1];
    int[][] curr = new int[m][k + 1];

    // Build DP table iteratively
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            for (int sum = 0; sum <= k; sum++) {

                // Base case
                if (i == 0 && j == 0) {
                    // Only one way if sum matches cell value
                    curr[j][sum] = (sum == mat[0][0]) ? 1 : 0;
                    continue;
                }

                curr[j][sum] = 0;

                if (sum - mat[i][j] >= 0) {
                    // from top
                    if (i > 0)
                        curr[j][sum] += prev[j][sum - mat[i][j]];
                    // from left
                    if (j > 0)
                        curr[j][sum] += curr[j - 1][sum - mat[i][j]];
                }
            }
        }

        // Move current row to previous row
        for (int j = 0; j < m; j++)
            prev[j] = Arrays.copyOf(curr[j], curr[j].length);
    }

    // Total ways to reach bottom-right with sum = k
    return prev[m - 1][k];
}

//Driver Code Starts public static void main(String[] args) { int k = 12; int[][] mat = { {1, 2, 3}, {4, 6, 5}, {3, 2, 1} };

    System.out.println(numberOfPath(mat, k));
}

}

//Driver Code Ends

Python

def numberOfPath(mat, k): n = len(mat) m = len(mat[0])

# Use only two 2D arrays for space optimization
prev = [[0] * (k + 1) for _ in range(m)]
curr = [[0] * (k + 1) for _ in range(m)]

# Build DP table iteratively
for i in range(n):
    for j in range(m):
        for sum_ in range(k + 1):

            # Base case
            if i == 0 and j == 0:
                # Only one way if sum matches cell value
                curr[j][sum_] = 1 if sum_ == mat[0][0] else 0
                continue

            curr[j][sum_] = 0

            if sum_ - mat[i][j] >= 0:
                # from top
                if i > 0:
                    curr[j][sum_] += prev[j][sum_ - mat[i][j]]
                # from left
                if j > 0:
                    curr[j][sum_] += curr[j - 1][sum_ - mat[i][j]]

    # Move current row to previous row
    prev = [row[:] for row in curr]

# Total ways to reach bottom-right with sum = k
return prev[m - 1][k]

#Driver Code Starts if name == "main": k = 12 mat = [ [1, 2, 3], [4, 6, 5], [3, 2, 1] ]

print(numberOfPath(mat, k))

#Driver Code Ends

C#

//Driver Code Starts using System;

class GFG { //Driver Code Ends

static int numberOfPath(int[,] mat, int k) {
    int n = mat.GetLength(0);
    int m = mat.GetLength(1);

    // Use only two 2D arrays for space optimization
    int[,] prev = new int[m, k + 1];
    int[,] curr = new int[m, k + 1];

    // Build DP table iteratively
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            for (int sum = 0; sum <= k; sum++) {
                
                // Base case
                if (i == 0 && j == 0) {
                    
                    // Only one way if sum matches cell value
                    curr[j, sum] = (sum == mat[0, 0]) ? 1 : 0;
                    continue;
                }

                curr[j, sum] = 0;

                if (sum - mat[i, j] >= 0) {
                    // from top
                    if (i > 0) curr[j, sum] += prev[j, sum - mat[i, j]];
                    // from left
                    if (j > 0) curr[j, sum] += curr[j - 1, sum - mat[i, j]];
                }
            }
        }

        // Move current row to previous row
        for (int j = 0; j < m; j++)
            for (int sum = 0; sum <= k; sum++)
                prev[j, sum] = curr[j, sum];
    }

    // Total ways to reach bottom-right with sum = k
    return prev[m - 1, k];
}

//Driver Code Starts static void Main() { int k = 12; int[,] mat = { {1, 2, 3}, {4, 6, 5}, {3, 2, 1} };

    Console.WriteLine(numberOfPath(mat, k));
}

}

//Driver Code Ends

JavaScript

function numberOfPath(mat, k) { const n = mat.length; const m = mat[0].length;

// Use only two 2D arrays for space optimization
let prev = Array.from({ length: m }, () => Array(k + 1).fill(0));
let curr = Array.from({ length: m }, () => Array(k + 1).fill(0));

// Build DP table iteratively
for (let i = 0; i < n; i++) {
    for (let j = 0; j < m; j++) {
        for (let sum = 0; sum <= k; sum++) {

            // Base case
            if (i === 0 && j === 0) {
                // Only one way if sum matches cell value
                curr[j][sum] = (sum === mat[0][0]) ? 1 : 0;
                continue;
            }

            curr[j][sum] = 0;

            if (sum - mat[i][j] >= 0) {

                // from top
                if (i > 0) curr[j][sum] += prev[j][sum - mat[i][j]];
                // from left
                if (j > 0) curr[j][sum] += curr[j - 1][sum - mat[i][j]];
            }
        }
    }

    // Move current row to previous row
    prev = curr.map(row => [...row]);
}

// Total ways to reach bottom-right with sum = k
return prev[m - 1][k];

}

// Driver Code //Driver Code Starts const k = 12; const mat = [ [1, 2, 3], [4, 6, 5], [3, 2, 1] ];

console.log(numberOfPath(mat, k));

//Driver Code Ends

`