Given an n x n integer matrix mat, we want to find the maximum difference mat[c][d] - mat[a][b] across all coordinate pairs (a, b) and (c, d) that satisfy the strict dominance condition c > a and d > b. In geometric terms, the second element mat[c][d] must lie strictly below and strictly to the right of the first element mat[a][b].
Problem Statement and Walkthrough Example
A naive brute-force search checks every valid pair of coordinates (a, b) and (c, d) in O(n^4) time, which times out when n = 1000 (where n^2 = 10^6 cells). By reformulating the query with 2D dynamic programming, we reduce the runtime to optimal O(n^2) time.
Example Matrix
Input: mat = [
[ 1, 2, -1, -4, -20 ],
[ -8, -3, 4, 2, 1 ],
[ 3, 8, 6, 1, 3 ],
[ -4, -1, 1, 7, -6 ],
[ 0, -4, 10, -5, 1 ]
]
Output: 18
Explanation:
Selecting (a, b) = (1, 0) where mat[1][0] = -8 and (c, d) = (4, 2) where mat[4][2] = 10
satisfies c > a (4 > 1) and d > b (2 > 0), yielding 10 - (-8) = 18.
Constraints
2 <= n <= 1000-1000 <= mat[i][j] <= 1000
2D Suffix Maximum Dynamic Programming Formulation
Suppose we fix the top-left coordinate (i, j). To maximize mat[c][d] - mat[i][j] over all c >= i + 1 and d >= j + 1, we simply need the largest value inside the bottom-right submatrix starting at (i + 1, j + 1) and extending to (n - 1, n - 1).
Define suffixMax[i][j] as the maximum element in the submatrix mat[i..n-1][j..n-1]. Moving from the bottom-right corner (n - 1, n - 1) toward the top-left corner (0, 0), we can compute suffixMax[i][j] in O(1) time per cell:
// Base cases on the last row and last column:
suffixMax[n - 1][n - 1] = mat[n - 1][n - 1];
suffixMax[n - 1][j] = max(mat[n - 1][j], suffixMax[n - 1][j + 1]);
suffixMax[i][n - 1] = max(mat[i][n - 1], suffixMax[i + 1][n - 1]);
// Interior transition for 0 <= i < n - 1 and 0 <= j < n - 1:
candidateDiff = suffixMax[i + 1][j + 1] - mat[i][j];
suffixMax[i][j] = max({ mat[i][j], suffixMax[i + 1][j], suffixMax[i][j + 1] });
C++20 Implementation (O(n^2) Time)
Below is the clean C++20 implementation using reverse matrix traversal from (n - 1, n - 1) to (0, 0):
#include <algorithm>
#include <climits>
#include <iostream>
#include <vector>
int findMaxPairDifference(const std::vector<std::vector<int>>& mat) {
const int n = static_cast<int>(mat.size());
std::vector<std::vector<int>> suffixMax(n, std::vector<int>(n, 0));
int maxDiff = INT_MIN;
// 1. Anchor bottom-right corner
suffixMax[n - 1][n - 1] = mat[n - 1][n - 1];
// 2. Precompute suffix maximums along the bottom row
for (int j = n - 2; j >= 0; --j) {
suffixMax[n - 1][j] = std::max(mat[n - 1][j], suffixMax[n - 1][j + 1]);
}
// 3. Precompute suffix maximums along the rightmost column
for (int i = n - 2; i >= 0; --i) {
suffixMax[i][n - 1] = std::max(mat[i][n - 1], suffixMax[i + 1][n - 1]);
}
// 4. Sweep interior cells from bottom-right to top-left
for (int i = n - 2; i >= 0; --i) {
for (int j = n - 2; j >= 0; --j) {
maxDiff = std::max(maxDiff, suffixMax[i + 1][j + 1] - mat[i][j]);
suffixMax[i][j] = std::max({
mat[i][j],
suffixMax[i + 1][j],
suffixMax[i][j + 1]
});
}
}
return maxDiff;
}
int main() {
std::vector<std::vector<int>> mat = {
{ 1, 2, -1, -4, -20 },
{ -8, -3, 4, 2, 1 },
{ 3, 8, 6, 1, 3 },
{ -4, -1, 1, 7, -6 },
{ 0, -4, 10, -5, 1 }
};
std::cout << "Maximum Difference: " << findMaxPairDifference(mat) << "\n"; // 18
return 0;
}
Space-Optimized TypeScript Implementation (O(n) Auxiliary Space)
Notice that computing row i of suffixMax only ever reads from row i + 1 (specifically suffixMax[i + 1][j + 1] and suffixMax[i + 1][j]) and the cell immediately to the right (suffixMax[i][j + 1]). We can therefore compress the 2D table into a single 1D rolling row of length n, cutting auxiliary memory from O(n^2) to O(n):
export function maxMatrixPairDifference(mat: ReadonlyArray<ReadonlyArray<number>>): number {
const n = mat.length;
if (n < 2) {
throw new Error('Matrix dimension n must be at least 2.');
}
// nextRow[j] holds suffixMax[i + 1][j]
const nextRow = new Int32Array(n);
nextRow[n - 1] = mat[n - 1][n - 1];
for (let j = n - 2; j >= 0; j--) {
nextRow[j] = Math.max(mat[n - 1][j], nextRow[j + 1]);
}
let maxDiff = -Infinity;
for (let i = n - 2; i >= 0; i--) {
let prevDiagSuffixMax = nextRow[n - 1]; // suffixMax[i + 1][j + 1]
nextRow[n - 1] = Math.max(mat[i][n - 1], nextRow[n - 1]);
for (let j = n - 2; j >= 0; j--) {
const belowSuffixMax = nextRow[j]; // suffixMax[i + 1][j] before overwrite
maxDiff = Math.max(maxDiff, prevDiagSuffixMax - mat[i][j]);
nextRow[j] = Math.max(mat[i][j], belowSuffixMax, nextRow[j + 1]);
prevDiagSuffixMax = belowSuffixMax;
}
}
return maxDiff;
}
Time and Space Complexity Comparison
| Approach | Time Complexity | Auxiliary Space | Notes |
|---|---|---|---|
| Brute-Force 4-Loop Search | O(n^4) |
O(1) |
Exceeds time limit for n > 80. |
| 2D Suffix Max Table | O(n^2) |
O(n^2) |
Visits each of the n^2 cells once in reverse order. |
| 1D Rolling Row Suffix Max | O(n^2) |
O(n) |
Optimal cache locality using a single Int32Array buffer. |
