Facebook Pixel

3148. Maximum Difference Score in a Grid


Problem Description

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.

Intuition

To solve this problem, we need to explore moving from one cell to another in the matrix while maximizing the score. The score of moving is defined as the difference between the value of the destination cell and the departure cell, c2 - c1.

We can define a path's score as the final cell value minus the starting cell value. Given this transformation, we aim to maximize the difference between the largest ending cell value and the smallest beginning cell value that can be reached as part of a valid path moving only down or to the right.

Breaking it down, we need to:

  1. Determine the smallest starting point value for paths ending at each cell (i, j).
  2. Keep track of this minimum value as we iterate through the matrix.

This can be done using dynamic programming. We'll maintain a 2D array f where f[i][j] stores the smallest starting point value for paths reaching cell (i, j). The dynamic programming transition will involve:

  • Considering the path value coming from either the top cell (i-1, j) or the left cell (i, j-1) while including the current cell's value grid[i][j].
  • Calculating the score as grid[i][j] - f[i][j] and maintaining the maximum score found.

The solution's crucial part is efficiently updating f[i][j] and the maximum score as we progress through the matrix.

Learn more about Dynamic Programming patterns.

Solution Approach

To implement the solution for this problem, we utilize a dynamic programming approach.

Dynamic Programming

The idea is to traverse through the matrix grid while keeping track of the minimum starting point for any path ending at each cell (i, j). We define a 2-dimensional list f where f[i][j] will hold this minimum starting cell value.

Here is a breakdown of the implementation:

  1. Initialization:

    • Initialize f as a matrix of the same dimensions as grid with all values set to zero.
    • Set ans to a very low value (negative infinity) which will eventually hold the maximum score.
  2. Traversal and State Transition:

    • Traverse each cell (i, j) in the grid.
    • For each cell, calculate the minimum starting point of the path that can end at (i, j).
    • This minimum value can come from the top (f[i-1][j]) or the left (f[i][j-1]) of the current cell. It is calculated as:
    f[i][j] = min(f[i-1][j], f[i][j-1], grid[i][j])
  3. Score Calculation:

    • Calculate the possible score for ending a path on cell (i, j) as grid[i][j] - f[i][j].
    • If this score is greater than the current ans, update ans.
  4. Return the Result:

    • After completing the traversal of the matrix, ans will contain the maximum score achievable, which we return.

This approach effectively tracks the potential starting point for any given endpoint, ensuring optimal scores for moves across the matrix.

Ready to land your dream job?

Unlock your dream job with a 2-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's consider a small example matrix grid:

grid = [
  [3, 5, 7],
  [1, 4, 6],
  [2, 8, 9]
]

We are applying a dynamic programming approach to find the maximum score possible.

  1. Initialization:

    • Create a matrix f with the same dimensions as grid initialized to store minimum starting values:

      f = [
        [0, 0, 0],
        [0, 0, 0],
        [0, 0, 0]
      ]
    • Set ans to negative infinity.

  2. Traversal and State Transition:

    • Start with the first row:

      • f[0][0] = grid[0][0] = 3
      • Calculate the score for grid[0][1]:
        f[0][1] = min(grid[0][0], grid[0][1]) = min(3, 5) = 3
        score = grid[0][1] - f[0][1] = 5 - 3 = 2
        ans = max(ans, score) = max(-inf, 2) = 2
      • Calculate score for grid[0][2]:
        f[0][2] = min(grid[0][1], grid[0][2]) = min(3, 7) = 3
        score = grid[0][2] - f[0][2] = 7 - 3 = 4
        ans = max(ans, 4) = 4
    • Move to the second row:

      • f[1][0] = min(grid[0][0], grid[1][0]) = min(3, 1) = 1
      • Calculate score for grid[1][1]:
        f[1][1] = min(f[0][1], f[1][0], grid[1][1]) = min(3, 1, 4) = 1
        score = grid[1][1] - f[1][1] = 4 - 1 = 3
        ans = max(ans, 3) = 4
      • Calculate score for grid[1][2]:
        f[1][2] = min(f[0][2], f[1][1], grid[1][2]) = min(3, 1, 6) = 1
        score = grid[1][2] - f[1][2] = 6 - 1 = 5
        ans = max(ans, 5) = 5
    • Move to the third row:

      • f[2][0] = min(f[1][0], grid[2][0]) = min(1, 2) = 1
      • Calculate score for grid[2][1]:
        f[2][1] = min(f[1][1], f[2][0], grid[2][1]) = min(1, 1, 8) = 1
        score = grid[2][1] - f[2][1] = 8 - 1 = 7
        ans = max(ans, 7) = 7
      • Calculate score for grid[2][2]:
        f[2][2] = min(f[1][2], f[2][1], grid[2][2]) = min(1, 1, 9) = 1
        score = grid[2][2] - f[2][2] = 9 - 1 = 8
        ans = max(ans, 8) = 8
  3. Result:

    • The maximum total score possible is 8, which is the value of ans after processing all cells.

Solution Implementation

1from typing import List
2from math import inf
3
4class Solution:
5    def maxScore(self, grid: List[List[int]]) -> int:
6        # Initialize a DP table with the same dimensions as the grid
7        f = [[0] * len(grid[0]) for _ in range(len(grid))]
8      
9        # Initialize the variable to track the maximum score
10        max_score = -inf
11      
12        # Iterate over each row in the grid
13        for i, row in enumerate(grid):
14            # Iterate over each element in the current row
15            for j, value in enumerate(row):
16                min_val = inf  # Start with an infinitely large minimum value
17              
18                # If not in the first row, update minimum value based on the cell above
19                if i > 0:
20                    min_val = min(min_val, f[i - 1][j])
21              
22                # If not in the first column, update the minimum value based on the previous cell in the row
23                if j > 0:
24                    min_val = min(min_val, f[i][j - 1])
25              
26                # Calculate the maximum score possible by subtracting the minimum path value found
27                max_score = max(max_score, value - min_val)
28              
29                # Update the DP table with the minimum value on the path to (i, j)
30                f[i][j] = min(value, min_val)
31      
32        return max_score
33
1import java.util.List;
2
3class Solution {
4    public int maxScore(List<List<Integer>> grid) {
5        // Define dimensions of the grid
6        int rows = grid.size(), columns = grid.get(0).size();
7      
8        // Define a large positive number representing infinity
9        final int infinity = 1 << 30;
10      
11        // Initialize the answer with negative infinity
12        int maxScore = -infinity;
13      
14        // Create a 2D array for dynamic programming
15        int[][] minSoFar = new int[rows][columns];
16      
17        // Traverse the grid row by row, column by column
18        for (int i = 0; i < rows; ++i) {
19            for (int j = 0; j < columns; ++j) {
20                // Initialize the minimum value with infinity
21                int currentMin = infinity;
22              
23                // Update currentMin to the minimum value reached till the cell (i, j)
24                if (i > 0) {
25                    currentMin = Math.min(currentMin, minSoFar[i - 1][j]);
26                }
27                if (j > 0) {
28                    currentMin = Math.min(currentMin, minSoFar[i][j - 1]);
29                }
30              
31                // Update maxScore considering the current cell's contribution
32                maxScore = Math.max(maxScore, grid.get(i).get(j) - currentMin);
33              
34                // Track the minimum value reachable to the cell (i, j)
35                minSoFar[i][j] = Math.min(grid.get(i).get(j), currentMin);
36            }
37        }
38      
39        // Return the maximum score
40        return maxScore;
41    }
42}
43
1class Solution {
2public:
3    int maxScore(vector<vector<int>>& grid) {
4        int rows = grid.size();         // Number of rows in the grid
5        int cols = grid[0].size();      // Number of columns in the grid
6        const int inf = 1 << 30;        // A large constant to simulate infinity
7        int maxScoreVal = -inf;         // Initialize the maximum score result
8        int minPathValue[rows][cols];   // Array to keep track of minimum path values
9
10        for (int i = 0; i < rows; ++i) {
11            for (int j = 0; j < cols; ++j) {
12                int minVal = inf;       // Minimum value encountered up to the current cell
13                if (i > 0) {
14                    // Check and update the minimum value from the top cell
15                    minVal = min(minVal, minPathValue[i - 1][j]);
16                }
17                if (j > 0) {
18                    // Check and update the minimum value from the left cell
19                    minVal = min(minVal, minPathValue[i][j - 1]);
20                }
21                // Calculate the potential max score for this position
22                maxScoreVal = max(maxScoreVal, grid[i][j] - minVal);
23                // Set the minimum path value for the current cell
24                minPathValue[i][j] = min(grid[i][j], minVal);
25            }
26        }
27
28        return maxScoreVal;  // Return the maximum score computed
29    }
30};
31
1function maxScore(grid: number[][]): number {
2    // Retrieve dimensions of the grid
3    const [m, n] = [grid.length, grid[0].length];
4  
5    // Initialize a 2D array f with the same dimensions as the grid, filled with 0
6    const f: number[][] = Array.from({ length: m }, () => Array.from({ length: n }, () => 0));
7
8    // Initialize the answer to negative infinity
9    let ans = -Infinity;
10
11    // Iterate over each cell in the grid
12    for (let i = 0; i < m; ++i) {
13        for (let j = 0; j < n; ++j) {
14            // Initialize minimum value for f as Infinity
15            let minValue = Infinity;
16
17            // If not on the first row, consider the value from the cell above
18            if (i) {
19                minValue = Math.min(minValue, f[i - 1][j]);
20            }
21
22            // If not on the first column, consider the value from the cell to the left
23            if (j) {
24                minValue = Math.min(minValue, f[i][j - 1]);
25            }
26
27            // Update the answer with the maximum score found so far
28            ans = Math.max(ans, grid[i][j] - minValue);
29
30            // Set the current cell in f to the minimum of the current grid value and the minimum value calculated
31            f[i][j] = Math.min(minValue, grid[i][j]);
32        }
33    }
34
35    // Return the maximum score
36    return ans;
37}
38

Time and Space Complexity

The time complexity of the code is O(m * n) because there are m rows and n columns in the grid, and the code iterates over each cell of the matrix exactly once. Within each iteration, only constant-time operations are performed, such as min and max calculations.

The space complexity of the code is also O(m * n) due to the auxiliary matrix f created to store intermediate results. This matrix is the same size as the input grid, requiring space proportional to the number of elements in the grid.

Learn more about how to find time and space complexity quickly.


Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:
Question 1 out of 10

A heap is a ...?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!


Load More