Maximum Difference Score in a Grid
MediumUpdated: Aug 2, 2025
Practice on:
Problem
You are given an m x n matrix grid consisting of positive integers.
You can move from a cell in the matrix to any other cell that is either to the bottom or to the right (not necessarily adjacent). The score of a move from a cell with the value c1 to a cell with the value c2 is c2 - c1.
You can start at any cell, and you have to make at least one move.
Return the maximum total score you can achieve.
Examples
Example 1

Input: grid = [[9,5,7,3],[8,9,6,1],[6,7,14,3],[2,5,3,1]]
Output: 9
Explanation: We start at the cell `(0, 1)`, and we perform the following
moves:
\- Move from the cell `(0, 1)` to `(2, 1)` with a score of `7 - 5 = 2`.
\- Move from the cell `(2, 1)` to `(2, 2)` with a score of `14 - 7 = 7`.
The total score is `2 + 7 = 9`.
Example 2

Input: grid = [[4,3,2],[3,2,1]]
Output: -1
Explanation: We start at the cell `(0, 0)`, and we perform one move: `(0,
0)` to `(0, 1)`. The score is `3 - 4 = -1`.
Constraints
m == grid.lengthn == grid[i].length2 <= m, n <= 10004 <= m * n <= 10^51 <= grid[i][j] <= 10^5
Solution
Method 1 – Dynamic Programming with Suffix Minimum
Intuition
To maximize the score, for each cell, we want to find the minimum value in the submatrix to its bottom-right (including itself), and then for each cell, check the difference between any cell to its right or below and itself. We can precompute the minimum value for each bottom-right submatrix using DP.
Approach
- Create a
min_sufmatrix wheremin_suf[i][j]is the minimum value in the submatrix starting at(i, j)to the bottom-right corner. - Fill
min_suffrom bottom-right to top-left. - For each cell
(i, j), check all possible moves to the right or below (i.e., any cell(x, y)withx >= iandy >= j), but we only need to check the minimum in the submatrix. - The maximum score is the maximum of
min_suf[x][y] - grid[i][j]for all valid moves. - Return the maximum score.
Code
C++
class Solution {
public:
int maxScore(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size();
vector<vector<int>> min_suf(m, vector<int>(n));
for (int i = m-1; i >= 0; --i) {
for (int j = n-1; j >= 0; --j) {
min_suf[i][j] = grid[i][j];
if (i+1 < m) min_suf[i][j] = min(min_suf[i][j], min_suf[i+1][j]);
if (j+1 < n) min_suf[i][j] = min(min_suf[i][j], min_suf[i][j+1]);
if (i+1 < m && j+1 < n) min_suf[i][j] = min(min_suf[i][j], min_suf[i+1][j+1]);
}
}
int ans = INT_MIN;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
if (i+1 < m) ans = max(ans, min_suf[i+1][j] - grid[i][j]);
if (j+1 < n) ans = max(ans, min_suf[i][j+1] - grid[i][j]);
}
}
return ans;
}
};
Go
func maxScore(grid [][]int) int {
m, n := len(grid), len(grid[0])
minSuf := make([][]int, m)
for i := range minSuf {
minSuf[i] = make([]int, n)
}
for i := m-1; i >= 0; i-- {
for j := n-1; j >= 0; j-- {
minSuf[i][j] = grid[i][j]
if i+1 < m && minSuf[i+1][j] < minSuf[i][j] {
minSuf[i][j] = minSuf[i+1][j]
}
if j+1 < n && minSuf[i][j+1] < minSuf[i][j] {
minSuf[i][j] = minSuf[i][j+1]
}
if i+1 < m && j+1 < n && minSuf[i+1][j+1] < minSuf[i][j] {
minSuf[i][j] = minSuf[i+1][j+1]
}
}
}
ans := math.MinInt32
for i := 0; i < m; i++ {
for j := 0; j < n; j++ {
if i+1 < m && minSuf[i+1][j]-grid[i][j] > ans {
ans = minSuf[i+1][j] - grid[i][j]
}
if j+1 < n && minSuf[i][j+1]-grid[i][j] > ans {
ans = minSuf[i][j+1] - grid[i][j]
}
}
}
return ans
}
Java
class Solution {
public int maxScore(int[][] grid) {
int m = grid.length, n = grid[0].length;
int[][] minSuf = new int[m][n];
for (int i = m-1; i >= 0; i--) {
for (int j = n-1; j >= 0; j--) {
minSuf[i][j] = grid[i][j];
if (i+1 < m) minSuf[i][j] = Math.min(minSuf[i][j], minSuf[i+1][j]);
if (j+1 < n) minSuf[i][j] = Math.min(minSuf[i][j], minSuf[i][j+1]);
if (i+1 < m && j+1 < n) minSuf[i][j] = Math.min(minSuf[i][j], minSuf[i+1][j+1]);
}
}
int ans = Integer.MIN_VALUE;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (i+1 < m) ans = Math.max(ans, minSuf[i+1][j] - grid[i][j]);
if (j+1 < n) ans = Math.max(ans, minSuf[i][j+1] - grid[i][j]);
}
}
return ans;
}
}
Kotlin
class Solution {
fun maxScore(grid: Array<IntArray>): Int {
val m = grid.size
val n = grid[0].size
val minSuf = Array(m) { IntArray(n) }
for (i in m-1 downTo 0) {
for (j in n-1 downTo 0) {
minSuf[i][j] = grid[i][j]
if (i+1 < m) minSuf[i][j] = minOf(minSuf[i][j], minSuf[i+1][j])
if (j+1 < n) minSuf[i][j] = minOf(minSuf[i][j], minSuf[i][j+1])
if (i+1 < m && j+1 < n) minSuf[i][j] = minOf(minSuf[i][j], minSuf[i+1][j+1])
}
}
var ans = Int.MIN_VALUE
for (i in 0 until m) {
for (j in 0 until n) {
if (i+1 < m) ans = maxOf(ans, minSuf[i+1][j] - grid[i][j])
if (j+1 < n) ans = maxOf(ans, minSuf[i][j+1] - grid[i][j])
}
}
return ans
}
}
Python
class Solution:
def maxScore(self, grid: list[list[int]]) -> int:
m, n = len(grid), len(grid[0])
min_suf = [[0]*n for _ in range(m)]
for i in range(m-1, -1, -1):
for j in range(n-1, -1, -1):
min_suf[i][j] = grid[i][j]
if i+1 < m:
min_suf[i][j] = min(min_suf[i][j], min_suf[i+1][j])
if j+1 < n:
min_suf[i][j] = min(min_suf[i][j], min_suf[i][j+1])
if i+1 < m and j+1 < n:
min_suf[i][j] = min(min_suf[i][j], min_suf[i+1][j+1])
ans = float('-inf')
for i in range(m):
for j in range(n):
if i+1 < m:
ans = max(ans, min_suf[i+1][j] - grid[i][j])
if j+1 < n:
ans = max(ans, min_suf[i][j+1] - grid[i][j])
return ans
Rust
impl Solution {
pub fn max_score(grid: Vec<Vec<i32>>) -> i32 {
let m = grid.len();
let n = grid[0].len();
let mut min_suf = vec![vec![0; n]; m];
for i in (0..m).rev() {
for j in (0..n).rev() {
min_suf[i][j] = grid[i][j];
if i+1 < m { min_suf[i][j] = min_suf[i][j].min(min_suf[i+1][j]); }
if j+1 < n { min_suf[i][j] = min_suf[i][j].min(min_suf[i][j+1]); }
if i+1 < m && j+1 < n { min_suf[i][j] = min_suf[i][j].min(min_suf[i+1][j+1]); }
}
}
let mut ans = i32::MIN;
for i in 0..m {
for j in 0..n {
if i+1 < m { ans = ans.max(min_suf[i+1][j] - grid[i][j]); }
if j+1 < n { ans = ans.max(min_suf[i][j+1] - grid[i][j]); }
}
}
ans
}
}
TypeScript
class Solution {
maxScore(grid: number[][]): number {
const m = grid.length, n = grid[0].length;
const minSuf = Array.from({length: m}, () => Array(n).fill(0));
for (let i = m-1; i >= 0; i--) {
for (let j = n-1; j >= 0; j--) {
minSuf[i][j] = grid[i][j];
if (i+1 < m) minSuf[i][j] = Math.min(minSuf[i][j], minSuf[i+1][j]);
if (j+1 < n) minSuf[i][j] = Math.min(minSuf[i][j], minSuf[i][j+1]);
if (i+1 < m && j+1 < n) minSuf[i][j] = Math.min(minSuf[i][j], minSuf[i+1][j+1]);
}
}
let ans = -Infinity;
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
if (i+1 < m) ans = Math.max(ans, minSuf[i+1][j] - grid[i][j]);
if (j+1 < n) ans = Math.max(ans, minSuf[i][j+1] - grid[i][j]);
}
}
return ans;
}
}
Complexity
- ⏰ Time complexity:
O(mn), wheremandnare the grid dimensions, since each cell is visited a constant number of times. - 🧺 Space complexity:
O(mn), for the suffix minimum matrix.