Post

Tree - Longest Increasing Path in a Matrix

All diagrams presented herein are original creations, meticulously designed to enhance comprehension and recall. Crafting these aids required considerable effort, and I kindly request attribution if this content is reused elsewhere.

Difficulty : Easy

DFS

Problem

Given an m x n integers matrix, return the length of the longest increasing path in matrix.

From each cell, you can either move in four directions: left, right, up, or down. You may not move diagonally or move outside the boundary (i.e., wrap-around is not allowed).

Constraints:

  • 0 <= matrix[i][j] <= 231 - 1

Example 1:

Image

1
2
3
Input: matrix = [[9,9,4],[6,6,8],[2,1,1]]
Output: 4
Explanation: The longest increasing path is [1, 2, 6, 9].

Example 2:

Image

1
2
3
Input: matrix = [[3,4,5],[3,2,6],[2,2,1]]
Output: 4
Explanation: The longest increasing path is [3, 4, 5, 6]. Moving diagonally is not allowed.

Example 3:

1
2
Input: matrix = [[1]]
Output: 1

Solution

Even though this problem is marked as hard in LeetCode its a simple problem. Let’s break in down in a step by step way. This is a graph traversal problem (like others we have seen) where we need to run dfs() [Not bfs() as we are looking for a single solution from one node] from every cell and find out which path is the largest.

So we need to save the max possible path from every cell. We can definitely use another matrix with same rows and cols to store this value. Later we can find which cell has the max value and just return that. For the Example 1 , it might look like this:

1
2
3
4
5
[
  [1,1,1],
  [2,2,2],
  [3,4,2]
]

So we can see the max is 4 which will be returned.

Now instead of creating a new matrix we can reuse our visited variable. Instead of creating a visited set we will create a visited map here.

1
2
ROWS, COLS = len(matrix),len(matrix[0])
visited={}

Next step is to write the dfs() for each cell. The dfs function takes the row, col and the previous value to compare as we need to make sure the current cell is greater than previous one, otherwise the dfs() needs to stop.

Start with the boundary conditions. Return 0 if any one the following condition can be met and do not traverse to the neighbors.

1
2
3
def dfs(r, c, prev):
  if r< 0 or c<0 or r==ROWS or c == COLS or matrix[r][c]<=prev:
    return 0

Next, if the matrix[r][c] > prev then traverse all four neighbors and find the which direction provides the max path length.

1
  max_path_so_far = max(dfs(r-1,c,matrix[r][c]), dfs(r+1,c,matrix[r][c]), dfs(r,c-1,matrix[r][c]),dfs(r,c+1,matrix[r][c]))

In case the matrix[r][c] is the only one which can be traversed, the max_path_so_far above will be 0 returned by the base condition we have written above. For an example, if 9 is being traversed, there is no where else to go since 9 is the highest number hence the max_path_so_far above will be 0.

We need to account for the cell matrix[r][c], so we will increment max_path_so_far by one. This way the visited[(r,c)] for 9 will be 1. Here are the values again.

Now let’s add the max_path_so_far to visited and return max_path_so_far.

1
2
  visited[(r,c)]=max_path_so_far
  return max_path_so_far

Now we need to run the dfs for each cell and populate visited map. We will pass -1 as the prev in the beginning as the lowest value can be 0. (Please refer the constraints above)

1
2
3
for r in range(ROWS):
  for c in range(COLS):
    dfs(r,c,-1) 

Finally, return the max value in the visited map.

1
return max(visited.values())

Logically the above code is going to work fine for smaller matrix, however for larger one its going to show Time Limit Exceeded error. One easy way to solve it is using cache. We can just return the cell max if available from the visited map, we do not have to traverse it anymore. This will save significant time. Let’s add that to the dfs() function before traversing all directions.

1
2
  if (r,c) in visited:
    return visited[(r,c)]

Final Code

Here is the full code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def longest_increasing_path(matrix) -> int:
    ROWS, COLS = len(matrix), len(matrix[0])
    visited = {}

    def dfs(r, c, prev):
        if r < 0 or c < 0 or r == ROWS or c == COLS or matrix[r][c] <= prev:
            return 0
				
        if (r,c) in visited:
          return visited[(r,c)]
        
        max_path_so_far = max(dfs(r-1, c, matrix[r][c]), dfs(r+1, c, matrix[r][c]),
                     dfs(r, c-1, matrix[r][c]), dfs(r, c+1, matrix[r][c]))
        max_path_so_far += 1

        visited[(r, c)] = max_path_so_far
        return max_path_so_far

    for r in range(ROWS):
        for c in range(COLS):
            dfs(r, c, -1)

    return max(visited.values())
This post is licensed under CC BY 4.0 by the author.