Number of Increasing Paths in a Grid

Updated on 14 July, 2025
Number of Increasing Paths in a Grid header image

Problem Statement

In the given task, you are provided with a two-dimensional integer matrix called grid of size m x n. You can move from any cell in this matrix to its adjacent cells in all four cardinal directions (up, down, left, and right). The objective is to find the number of strictly increasing paths in this grid. A path is considered strictly increasing if each subsequent value in the path is larger than the preceding one. Notably, a path can commence and terminate at any cell in the grid.

To cater to the potentially large output, the solution must be calculated modulo 1,000,000,007 (109 + 7). Paths are identified distinctly based on their exact sequence of visited cells, which means paths visiting the same cells but in different order or starting and ending at different cells are counted separately.

Examples

Example 1

Input:

grid = [[1,1],[3,4]]

Output:

8

Explanation:

The strictly increasing paths are:
- Paths with length 1: [1], [1], [3], [4].
- Paths with length 2: [1 -> 3], [1 -> 4], [3 -> 4].
- Paths with length 3: [1 -> 3 -> 4].
The total number of paths is 4 + 3 + 1 = 8.

Example 2

Input:

grid = [[1],[2]]

Output:

3

Explanation:

The strictly increasing paths are:
- Paths with length 1: [1], [2].
- Paths with length 2: [1 -> 2].
The total number of paths is 2 + 1 = 3.

Constraints

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 1000
  • 1 <= m * n <= 105
  • 1 <= grid[i][j] <= 105

Approach and Intuition

To solve this problem, understanding the flow and directionality within the grid is critical:

  1. Naive Depth-First Search (DFS) Approach:

    • Starting at each cell, attempt to move to all adjacent cells.
    • For each move, ensure the next cell has a greater value to maintain the strictly increasing condition.
    • Use recursion to explore all valid paths from the starting cell.
  2. Optimization with Dynamic Programming (DP):

    • Utilize a DP array where dp[i][j] holds the number of increasing paths starting from cell (i, j).
    • Populate this array by checking all four possible directions and adding counts of increasing paths from adjacent cells, provided those cells contain a larger number than the current one.
    • Important edge cases include handling cells that don't have any cell larger around them (i.e., local maxima in the grid).
  3. Modular Arithmetic:

    • Since the result needs modulo 1,000,000,007, incorporate this operation during additions to prevent integer overflow.
  4. Handling Paths of Length 1:

    • Every single cell can be considered a path of length 1. Start by initializing each cell's path count to 1.
  5. Implementation Detail:

    • Iteratively or recursively update the DP array. For a recursive approach, caching results (memoization) would be crucial to prevent redundant calculations.
    • Fill the DP array and sum up all values for the final count of increasing paths.

As we analyze the problem with these considerations, we recognize the complexity not only lies in the recursive traversal but also in efficiently storing and summing path information without unnecessary recomputation. By employing a strategic combination of DFS for path exploration and DP for storing intermediate results, we can tackle the problem efficiently even for larger grid sizes within the provided constraints.

Solutions

  • Java
java
class Solution {
    int[][] memoization;
    int[][] moves = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
    int modulus = 1_000_000_007;
        
    int depthFirstSearch(int[][] matrix, int x, int y) {
        if (memoization[x][y] != -1)
            return memoization[x][y];
    
        int pathCount = 1;
        for (int[] move : moves) {
            int newX = x + move[0], newY = y + move[1];
            if (newX >= 0 && newX < matrix.length && newY >= 0 && 
                newY < matrix[0].length && matrix[newX][newY] < matrix[x][y]) {
                pathCount = (pathCount + depthFirstSearch(matrix, newX, newY)) % modulus;
            }
        }
    
        memoization[x][y] = pathCount;
        return pathCount;
    }
        
    public int totalPaths(int[][] matrix) {
        int rows = matrix.length, cols = matrix[0].length;
        memoization = new int[rows][cols];
            
        for (int i = 0; i < rows; ++i) {
            for (int j = 0; j < cols; ++j) {
                memoization[i][j] = -1;
            }
        }
    
        int totalPathCount = 0;
        for (int i = 0; i < rows; ++i) {
            for (int j = 0; j < cols; ++j) {
                totalPathCount = (totalPathCount + depthFirstSearch(matrix, i, j)) % modulus;
            }
        }
    
        return totalPathCount;
    }
}

In the provided Java solution, the objective is to calculate the number of increasing paths in a grid using a depth-first search (DFS) approach combined with memoization. Here’s an outline and explanation of how this operation is structurally performed:

  • Initialization of Data Structures:

    • memoization: A 2D array to store the number of paths from each cell, initialized to -1 which indicates that the number of paths has not yet been calculated for that cell.
    • moves: An array representing the four possible movements from a cell (right, down, left, up).
  • Depth-First Search (DFS) Function:

    • The function depthFirstSearch checks if a cell's path count is already computed by seeing if memoization[x][y] is not -1. If not cached, it computes the paths by exploring all valid adjacent cells that have a greater value than the current cell, recursively calculating the number of paths from these cells.
    • Each cell starts with a path count of 1 (the cell itself).
    • The recursive nature, combined with memoization, ensures each cell's paths are computed only once, improving efficiency.
  • Calculation of Total Paths:

    • The totalPaths function initializes the memoization matrix and iterates through each cell of the grid.
    • It invokes depthFirstSearch for each cell to compute the total number of paths starting from that cell and aggregates these into totalPathCount.
    • Modular arithmetic is used (modulus 1,000,000,007) to prevent overflow and manage large numbers which is common in combinatorial problems.
  • Modular Arithmetic:

    • The use of modulus (1_000_000_007), a large prime number, is a common technique to keep numbers within integer bounds and is particularly useful in interview settings and competitive programming.

By initializing and strategically caching results, this approach efficiently handles the computation of increasing paths in potentially large matrices. The granularity and strategic checks prevent unnecessary recalculations, deeming this solution optimal for performance-sensitive environments.

  • Python
python
class Solution:
    def calculatePaths(self, matrix: List[List[int]]) -> int:
        rows, cols = len(matrix), len(matrix[0])
        modulus = 1000000007
        movements = [[0, 1], [1, 0], [0, -1], [-1, 0]]
            
        memory = [[-1] * cols for _ in range(rows)]
            
        def explore(x, y):
            if memory[x][y] != -1:
                return memory[x][y]
                
            path_count = 1
            for dx, dy in movements:
                nx, ny = x + dx, y + dy
                if 0 <= nx < rows and 0 <= ny < cols and matrix[nx][ny] < matrix[x][y]:
                    path_count += explore(nx, ny) % modulus
                
            memory[x][y] = path_count
            return path_count
            
        total_paths = sum(explore(r, c) for r in range(rows) for c in range(cols)) % modulus
        return total_paths

In the provided Python solution, you calculate the number of increasing paths within a grid using depth-first search (DFS) and dynamic programming. The solution employs a memorization technique to store previously computed values, optimizing the performance by avoiding redundant calculations.

  • Define the number of rows and columns from the input matrix.
  • Initialize a modulus to handle potential integer overflow issues by taking results modulo 10^9 + 7.
  • Assign the possible movements in the grid (right, down, left, up).
  • Create a 2D list memory initialized with -1, used to store the number of paths from any cell (x, y).

For each cell in the grid, the explore function is used to calculate the paths recursively:

  • If the value in memory for the current cell is not -1, return the memorized result to avoid recalculating.
  • Initialize path_count to 1, representing the path of standing still.
  • Traverse through all possible movements, and for each valid movement (staying within bounds and ensuring that the path is increasing), recursively calculate the number of paths from the next cell.
  • The count of paths from each direction is added to path_count.
  • Store path_count in memory[x][y] and return this value.

Finally, compute the total number of paths across all cells in the grid by iterating through each cell, invoking explore, and summing up results. Apply modulo operation to ensure the result is within the required bounds before returning it.

Comments

No comments yet.