Given an N × N matrix where each cell has a distinct value in the 1 to N × N. Find the longest sequence formed by adjacent numbers in the matrix such that for each number, the number on the adjacent neighbor is +1 in its value.

If we are at location (x, y) in the matrix, we can move to (x, y+1), (x, y-1), (x+1, y), or (x-1, y) if the value at the destination cell is one more than the value at source cell. For example, the longest sequence formed by adjacent numbers in the following matrix is [2, 3, 4, 5, 6, 7]:

 
Longest path in matrix
 

Practice this problem

 
The idea is to use recursion. The problem has optimal substructure. That means the problem can be broken down into smaller, simple “subproblems”, which can further be divided into yet simpler, smaller subproblems until the solution becomes trivial. We can recursively define the problem as:

The longest path starting from cell (i, j) =
 
M[i][j] + | longest path starting from cell (i-1, j)   (if M[i][j] + 1 = M[i-1][j])
          | longest path starting from cell (i, j-1)   (if M[i][j] + 1 = M[i][j-1])
          | longest path starting from cell (i, j+1)   (if M[i][j] + 1 = M[i][j+1])
          | longest path starting from cell (i+1, j)   (if M[i][j] + 1 = M[i+1][j])

This is demonstrated below in C++, Java, and Python:

C++


Download  Run Code

Output:

[2, 3, 4, 5, 6, 7]

Java


Download  Run Code

Output:

[2, 3, 4, 5, 6, 7]

Python


Download  Run Code

Output:

[2, 3, 4, 5, 6, 7]

The implementation that involves only finding the length of the longest sequence can be seen here.

 
The time complexity of the proposed solution is exponential as we are doing a lot of redundant work. As we are calculating the longest path starting from each cell (i, j) of the matrix. Therefore,

The longest path starting from 2 is (2 — 3 — 4 — 5 — 6 — 7)
The longest path starting from 3 is (3 — 4 — 5 — 6 — 7)
The longest path starting from 5 is (5 — 6 — 7)
The longest path starting from 4 is (4 — 5 — 6 — 7)
The longest path starting from 6 is (6 — 7)
The longest path starting from 2 is (2 — 3 — 4 — 5 — 6 — 7)
The longest path starting from 3 is (3 — 4 — 5 — 6 — 7)
The longest path starting from 5 is (5 — 6 — 7)
The longest path starting from 4 is (4 — 5 — 6 — 7)
The longest path starting from 6 is (6 — 7)
The longest path starting from 2 is (2 — 3 — 4 — 5 — 6 — 7)
The longest path starting from 3 is (3 — 4 — 5 — 6 — 7)
The longest path starting from 5 is (5 — 6 — 7)
The longest path starting from 4 is (4 — 5 — 6 — 7)
The longest path starting from 6 is (6 — 7)
The longest path starting from 2 is (2 — 3 — 4 — 5 — 6 — 7)
The longest path starting from 3 is (3 — 4 — 5 — 6 — 7)
The longest path starting from 5 is (5 — 6 — 7)
The longest path starting from 4 is (4 — 5 — 6 — 7)
The longest path starting from 6 is (6 — 7)

As we can see, the same subproblems are getting computed repeatedly. As the recursion grows deeper, more and more of this type of unnecessary repetition occurs. We know that problems having optimal substructure and overlapping subproblems can be solved by dynamic programming, in which subproblem solutions are memoized rather than computed repeatedly. Now each time we compute the longest path starting from cell (i, j), save it. If we are ever asked to compute it again, give the saved answer and do not recompute it.

The implementation can be seen below in C++, Java, and Python:

C++


Download  Run Code

Output:

2, 3, 4, 5, 6, 7

Java


Download  Run Code

Output:

2, 3, 4, 5, 6, 7

Python


Download  Run Code

Output:

2, 3, 4, 5, 6, 7

The time complexity of the proposed solution is O(N2) for an N × N matrix. The auxiliary space required by the program is O(N2).

 
Exercise: Extend the solution to consider diagonal moves as well.