You are given a 2D matrix grid
of size n x n
. Initially, all cells of the grid are colored white. In one operation, you can select any cell of indices (i, j)
, and color black all the cells of the jth
column starting from the top row down to the ith
row.
The grid score is the sum of all grid[i][j]
such that cell (i, j)
is white and it has a horizontally adjacent black cell.
Return the maximum score that can be achieved after some number of operations.
Example 1:
Input: grid = [[0,0,0,0,0],[0,0,3,0,0],[0,1,0,0,0],[5,0,0,3,0],[0,0,0,0,2]]
Output: 11
Explanation:
In the first operation, we color all cells in column 1 down to row 3, and in the second operation, we color all cells in column 4 down to the last row. The score of the resulting grid is grid[3][0] + grid[1][2] + grid[3][3]
which is equal to 11.
Example 2:
Input: grid = [[10,9,0,0,15],[7,1,0,8,0],[5,20,0,11,0],[0,0,0,1,2],[8,12,1,10,3]]
Output: 94
Explanation:
We perform operations on 1, 2, and 3 down to rows 1, 4, and 0, respectively. The score of the resulting grid is grid[0][0] + grid[1][0] + grid[2][1] + grid[4][1] + grid[1][3] + grid[2][3] + grid[3][3] + grid[4][3] + grid[0][4]
which is equal to 94.
Constraints:
1 <= n == grid.length <= 100
n == grid[i].length
0 <= grid[i][j] <= 109
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force strategy for maximizing the score from grid operations involves exploring every possible path from the starting point to the end. It's like trying out all the routes you could take through a maze to find the one that gives you the highest score.
Here's how the algorithm would work step-by-step:
def maximum_score_from_grid_operations_brute_force(grid): number_of_rows = len(grid)
number_of_columns = len(grid[0])
def get_all_possible_paths(row_index, column_index, current_score):
# If we reach the end of the grid, return the score.
if row_index == number_of_rows - 1 and column_index == number_of_columns - 1:
return current_score + grid[row_index][column_index]
#If the current cell is out of bounds, return negative infinity.
if row_index < 0 or row_index >= number_of_rows or column_index < 0 or column_index >= number_of_columns:
return float('-inf')
current_score += grid[row_index][column_index]
grid_value = grid[row_index][column_index]
grid[row_index][column_index] = 0 # Mark as visited
# Explore all possible paths from the current cell.
up = get_all_possible_paths(row_index - 1, column_index, current_score)
down = get_all_possible_paths(row_index + 1, column_index, current_score)
left = get_all_possible_paths(row_index, column_index - 1, current_score)
right = get_all_possible_paths(row_index, column_index + 1, current_score)
grid[row_index][column_index] = grid_value # Backtrack
# Find the maximum score among all paths.
return max(up, down, left, right)
# Initiate brute force search for all possible paths from start point
maximum_score = get_all_possible_paths(0, 0, 0)
return maximum_score
The goal is to find the highest possible score you can get by moving through a grid, adding and subtracting values. The best way to solve this is to realize it's a classic pathfinding problem where we can avoid recomputing scores using dynamic programming, saving a lot of time.
Here's how the algorithm would work step-by-step:
def max_score_from_grid_operations(grid):
number_of_rows = len(grid)
number_of_columns = len(grid[0])
# This table stores the maximum score to reach each cell.
maximum_score_table = [([0] * number_of_columns) for _ in range(number_of_rows)]
maximum_score_table[0][0] = grid[0][0]
# Initialize first row.
for column_index in range(1, number_of_columns):
maximum_score_table[0][column_index] = maximum_score_table[0][column_index - 1] + grid[0][column_index]
# Initialize first column.
for row_index in range(1, number_of_rows):
maximum_score_table[row_index][0] = maximum_score_table[row_index - 1][0] + grid[row_index][0]
# Fill the table using dynamic programming.
for row_index in range(1, number_of_rows):
for column_index in range(1, number_of_columns):
# Choose the path with the max score from top/left.
maximum_score_table[row_index][column_index] = max(
maximum_score_table[row_index - 1][column_index],
maximum_score_table[row_index][column_index - 1],
) + grid[row_index][column_index]
# Result holds maximum score to reach bottom right.
return maximum_score_table[number_of_rows - 1][number_of_columns - 1]
Case | How to Handle |
---|---|
Null or empty grid | Return 0 if the grid is null or empty, as there are no cells to visit. |
Grid with only one row or one column | Iterate through the single row or column and sum the values. |
1x1 grid | Return the single cell's value directly. |
Grid with negative numbers | The dynamic programming approach should correctly handle negative numbers, potentially leading to negative maximum scores. |
Grid with all zeros | The DP solution will correctly compute a maximum score of 0. |
Integer overflow in score calculation | Use a larger data type (e.g., long) for the score to avoid integer overflow. |
Large grid dimensions that cause memory issues with DP | The DP table should be allocated within available memory limits, and the complexity should be analyzed beforehand. |
Grid with extremely large positive and negative values | Ensure that the chosen data type for storing cell values and the accumulated score can accommodate these extreme values without overflow or loss of precision. |