cconnected.
Understand the pattern. Find your own way.Find your starting point
Your learning feed/Idea 109 of 218
Ideas this builds on
Thinking in DP109 / 218

Longest Increasing Path in a Matrix

Picture

In [[1,2],[4,3]], the increasing route 1→2→3→4 moves right, down, and left. A row-by-row grid DP would not respect its dependencies. But strict increase means the directed movement graph cannot have a cycle.

Predict

What is the best route length starting at a cell with no larger neighbor?

Walk through the small example

One: the cell itself. Other cells can add themselves to the best larger-neighbor continuation.

Mental model and complete Python solution

Define length[u]=1+max(length[v]) over larger neighbors, with empty maximum zero. Those larger-neighbor answers must be ready first. Count each cell’s larger neighbors, seed local maxima with length one, and process them in a reverse topological queue. A finished cell offers length+1 to each smaller neighbor; that neighbor becomes ready when all of its larger neighbors are processed. This computes the same recurrence as memoized DFS without a potentially RC-deep Python call stack.

What the function promises: A nonempty rectangular matrix permits four-direction moves only to strictly larger values. Return the maximum number of cells in a valid path. Empty input returns zero as a helper extension.

from collections import deque

def longest_increasing_path(matrix):
    if not matrix or not matrix[0]:
        return 0
    rows, cols = len(matrix), len(matrix[0])

    def neighbors(r, c):
        for nr, nc in ((r-1,c), (r+1,c), (r,c-1), (r,c+1)):
            if 0 <= nr < rows and 0 <= nc < cols:
                yield nr, nc

    larger = [[0] * cols for _ in range(rows)]
    length = [[1] * cols for _ in range(rows)]
    ready = deque()
    for r in range(rows):
        for c in range(cols):
            larger[r][c] = sum(matrix[nr][nc] > matrix[r][c]
                               for nr, nc in neighbors(r, c))
            if larger[r][c] == 0:
                ready.append((r, c))
    answer = 1
    while ready:
        r, c = ready.popleft()
        answer = max(answer, length[r][c])
        for nr, nc in neighbors(r, c):
            if matrix[nr][nc] < matrix[r][c]:
                length[nr][nc] = max(length[nr][nc], length[r][c] + 1)
                larger[nr][nc] -= 1
                if larger[nr][nc] == 0:
                    ready.append((nr, nc))
    return answer

assert longest_increasing_path([[1,2], [4,3]]) == 4
assert longest_increasing_path([[7,7], [7,7]]) == 1
assert longest_increasing_path([[1,2,3,4,5]]) == 5
assert longest_increasing_path([]) == 0

Work and storage: O(RC) time and space; each cell and its at-most-four edges are processed a constant number of times. Sorting by value would also supply a valid order but adds logarithmic sorting work.

When to recognize it: An edge always leads to a bigger value. A cycle would need to become bigger and return to the same value: impossible.

Check before applying it: Allowing equal or decreasing values removes the strict-progress proof. Ordinary memoization is not a general solution to cyclic longest paths.

Change one rule

Equal-valued moves become legal and revisits remain allowed. Does the recurrence still define a finite longest walk?

See what changes

Not necessarily. Two equal adjacent cells allow arbitrarily many back-and-forth steps. If instead revisits are forbidden, the problem becomes a longest-simple-path problem and generally needs additional history; a memo keyed only by cell is no longer justified.

Connect

Parallel Courses III: Reuse longest-path reasoning after discovering the hidden DAG.

Shortest Path in a Grid with Obstacles Elimination: Four grid directions alone do not tell you whether to use DP or BFS.

Problem reference: Longest Increasing Path in a Matrix (Hard). The walkthrough and Python solution above are original course material.