1975. Maximum Matrix Sum
Problem Description
You have an n x n
integer matrix, and you can perform a special operation as many times as you want. The operation allows you to pick any two adjacent elements in the matrix (elements that share a border - horizontally or vertically next to each other) and multiply both of them by -1
. This flips the sign of both elements simultaneously.
Your task is to find the maximum possible sum of all elements in the matrix after performing this operation any number of times (including zero times).
For example, if you have two adjacent elements [3, -5]
, after applying the operation once, they become [-3, 5]
. The key insight is that this operation always flips the signs of exactly two elements at once.
The solution uses a greedy approach based on counting negative numbers. Since each operation flips two signs at once, if you have an even number of negative elements, you can make all elements positive. If you have an odd number of negative elements, exactly one element must remain negative in the final configuration. In this case, you'd want the negative element to be the one with the smallest absolute value to maximize the total sum.
The code tracks:
cnt
: the count of negative numbersmi
: the minimum absolute value among all elementss
: the sum of absolute values of all elements
If cnt
is even, all elements can be made positive, so return s
. If cnt
is odd, one element must stay negative, so return s - 2 * mi
(subtracting the smallest absolute value twice accounts for removing it from the positive sum and adding it as negative).
Intuition
Let's think about what happens when we apply the operation. Each operation flips the signs of exactly two adjacent elements. This means:
- If both elements are positive, they become negative (sum decreases)
- If both elements are negative, they become positive (sum increases)
- If one is positive and one is negative, they swap signs (sum may increase or decrease)
The key observation is that each operation changes the parity of negative numbers by either 0 or 2. If we start with an even number of negative elements, we'll always have an even number after any operation. Similarly, if we start with odd, we'll always have odd.
Now, what's the best possible outcome? Ideally, we want all elements to be positive to maximize the sum. Can we achieve this?
- If we have an even number of negative elements: Yes! We can pair them up and flip each pair to positive.
- If we have an odd number of negative elements: No matter how we operate, we'll always have an odd number, meaning at least one must remain negative.
For the odd case, which element should remain negative? To maximize the sum, we want to minimize the loss, so we should keep the element with the smallest absolute value as negative.
This leads us to the strategy:
- Count the negative numbers to determine parity
- Find the element with minimum absolute value (in case we need to keep one negative)
- Calculate the sum of all absolute values
- If odd number of negatives, subtract twice the minimum absolute value (once to remove it from the positive sum, once to add it as negative)
This greedy approach works because the operation gives us enough flexibility to rearrange signs optimally while respecting the parity constraint.
Learn more about Greedy patterns.
Solution Approach
The implementation follows a greedy strategy based on the parity of negative numbers in the matrix.
Algorithm Steps:
-
Initialize tracking variables:
mi = inf
: Track the minimum absolute value across all elementss = 0
: Accumulate the sum of absolute valuescnt = 0
: Count the number of negative elements
-
Single pass through the matrix:
for row in matrix: for x in row:
For each element
x
:- Count negative numbers:
cnt += x < 0
(adds 1 if negative, 0 if non-negative) - Calculate absolute value:
y = abs(x)
- Update minimum absolute value:
mi = min(mi, y)
- Add to total sum:
s += y
- Count negative numbers:
-
Determine final result based on parity:
return s if cnt % 2 == 0 else s - mi * 2
- If
cnt % 2 == 0
(even number of negatives): All elements can be made positive, returns
- If
cnt % 2 == 1
(odd number of negatives): One element must remain negative- We subtract
mi * 2
froms
because:- We already added
mi
tos
as positive - We need to remove it (
-mi
) and add it as negative (-mi
) - Total adjustment:
-2 * mi
- We already added
- We subtract
- If
Time Complexity: O(nΒ²)
where n is the dimension of the matrix, as we visit each element once.
Space Complexity: O(1)
as we only use a constant amount of extra space for variables.
The elegance of this solution lies in recognizing that we don't need to simulate the actual operations. We only need to determine the final configuration based on the parity constraint and greedily choose the optimal element to remain negative if needed.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a concrete example with a 2x2 matrix:
Initial matrix: [[2, -3], [-5, 4]]
Step 1: Analyze the initial state
- Count negative numbers: 2 (the -3 and -5)
- Calculate absolute values: [[2, 3], [5, 4]]
- Sum of absolute values: 2 + 3 + 5 + 4 = 14
- Minimum absolute value: 2
Step 2: Determine what's possible Since we have 2 negative numbers (even count), we can make all elements positive through operations.
Step 3: Demonstrate how to achieve all positive (for understanding)
- Apply operation on -3 and -5 (they're adjacent vertically):
[[2, -3], β [[2, 3], [-5, 4]] [5, 4]]
- Now all elements are positive! Sum = 2 + 3 + 5 + 4 = 14
Step 4: Apply our algorithm
- cnt = 2 (even)
- s = 14 (sum of absolute values)
- mi = 2 (minimum absolute value)
- Since cnt is even: return s = 14
Now let's try an example with odd negatives:
Initial matrix: [[1, -2], [3, 4]]
Step 1: Analyze
- Count negative numbers: 1 (only -2)
- Sum of absolute values: 1 + 2 + 3 + 4 = 10
- Minimum absolute value: 1
Step 2: Determine what's possible With 1 negative number (odd count), we must keep exactly one element negative after all operations.
Step 3: Find optimal configuration We want the smallest absolute value (1) to be negative to minimize loss:
- Apply operation on 1 and -2:
[[1, -2], β [[-1, 2], [3, 4]] [3, 4]]
- Final sum = -1 + 2 + 3 + 4 = 8
Step 4: Apply our algorithm
- cnt = 1 (odd)
- s = 10 (sum of absolute values)
- mi = 1 (minimum absolute value)
- Since cnt is odd: return s - 2mi = 10 - 21 = 8
The algorithm correctly identifies that with an odd number of negatives, we lose 2 Γ (minimum absolute value) from the maximum possible sum.
Solution Implementation
1class Solution:
2 def maxMatrixSum(self, matrix: List[List[int]]) -> int:
3 # Track the smallest absolute value in the matrix
4 min_absolute_value = float('inf')
5
6 # Track the sum of absolute values and count of negative numbers
7 total_absolute_sum = 0
8 negative_count = 0
9
10 # Iterate through all elements in the matrix
11 for row in matrix:
12 for value in row:
13 # Count negative numbers
14 if value < 0:
15 negative_count += 1
16
17 # Get absolute value of current element
18 absolute_value = abs(value)
19
20 # Update minimum absolute value seen so far
21 min_absolute_value = min(min_absolute_value, absolute_value)
22
23 # Add to total sum of absolute values
24 total_absolute_sum += absolute_value
25
26 # If even number of negatives, we can make all values positive
27 # If odd number of negatives, one value must remain negative (choose the smallest)
28 if negative_count % 2 == 0:
29 return total_absolute_sum
30 else:
31 return total_absolute_sum - 2 * min_absolute_value
32
1class Solution {
2 public long maxMatrixSum(int[][] matrix) {
3 // Total sum of absolute values
4 long totalSum = 0;
5
6 // Track the minimum absolute value in the matrix
7 int minAbsValue = Integer.MAX_VALUE;
8
9 // Count of negative numbers
10 int negativeCount = 0;
11
12 // Iterate through each row in the matrix
13 for (int[] row : matrix) {
14 // Iterate through each element in the row
15 for (int element : row) {
16 // Count negative numbers
17 if (element < 0) {
18 negativeCount++;
19 }
20
21 // Get absolute value of current element
22 int absoluteValue = Math.abs(element);
23
24 // Update minimum absolute value
25 minAbsValue = Math.min(minAbsValue, absoluteValue);
26
27 // Add absolute value to total sum
28 totalSum += absoluteValue;
29 }
30 }
31
32 // If even number of negatives, all can be made positive
33 // If odd number of negatives, one value must remain negative (choose the smallest)
34 if (negativeCount % 2 == 0) {
35 return totalSum;
36 } else {
37 // Subtract twice the minimum value (once to remove it from sum, once for negative)
38 return totalSum - 2 * minAbsValue;
39 }
40 }
41}
42
1class Solution {
2public:
3 long long maxMatrixSum(vector<vector<int>>& matrix) {
4 // Initialize sum of absolute values
5 long long totalSum = 0;
6
7 // Track the minimum absolute value and count of negative numbers
8 int minAbsValue = INT_MAX;
9 int negativeCount = 0;
10
11 // Iterate through each row in the matrix
12 for (const auto& row : matrix) {
13 // Process each element in the current row
14 for (int value : row) {
15 // Count negative numbers
16 if (value < 0) {
17 negativeCount++;
18 }
19
20 // Get absolute value of current element
21 int absValue = abs(value);
22
23 // Update minimum absolute value seen so far
24 minAbsValue = min(minAbsValue, absValue);
25
26 // Add absolute value to total sum
27 totalSum += absValue;
28 }
29 }
30
31 // If even number of negatives, all can be made positive
32 // If odd number of negatives, one must remain negative (choose the smallest)
33 if (negativeCount % 2 == 0) {
34 return totalSum;
35 } else {
36 // Subtract twice the minimum to account for it being negative instead of positive
37 return totalSum - 2 * minAbsValue;
38 }
39 }
40};
41
1/**
2 * Calculates the maximum sum of a matrix after applying allowed operations.
3 * Operations allow multiplying any adjacent pair of elements by -1.
4 *
5 * @param matrix - 2D array of integers
6 * @returns The maximum possible sum after any number of operations
7 */
8function maxMatrixSum(matrix: number[][]): number {
9 // Initialize variables:
10 // totalSum: sum of absolute values of all elements
11 // negativeCount: count of negative numbers in the matrix
12 // minAbsValue: smallest absolute value in the matrix
13 let totalSum: number = 0;
14 let negativeCount: number = 0;
15 let minAbsValue: number = Infinity;
16
17 // Iterate through each row in the matrix
18 for (const row of matrix) {
19 // Process each element in the current row
20 for (const element of row) {
21 // Count negative numbers
22 if (element < 0) {
23 negativeCount++;
24 }
25
26 // Calculate absolute value of current element
27 const absoluteValue: number = Math.abs(element);
28
29 // Add absolute value to total sum
30 totalSum += absoluteValue;
31
32 // Track the minimum absolute value
33 minAbsValue = Math.min(minAbsValue, absoluteValue);
34 }
35 }
36
37 // If even number of negatives, all can be eliminated
38 // If odd number of negatives, one must remain - choose the smallest
39 return negativeCount % 2 === 0 ? totalSum : totalSum - 2 * minAbsValue;
40}
41
Time and Space Complexity
The time complexity is O(m Γ n)
, where m
is the number of rows and n
is the number of columns of the matrix. This is because the algorithm uses nested loops to iterate through every element in the matrix exactly once - the outer loop iterates through each row, and the inner loop iterates through each element in that row.
The space complexity is O(1)
. The algorithm only uses a constant amount of extra space regardless of the input size. The variables mi
, s
, and cnt
are single values that don't scale with the size of the input matrix. No additional data structures are created that depend on the matrix dimensions.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Misunderstanding the Operation's Constraint
Pitfall: A common mistake is thinking you can flip the sign of any single element independently. The operation MUST flip exactly two adjacent elements simultaneously. This constraint is crucial because it means:
- You cannot change just one element's sign in isolation
- The total number of negative elements changes by either 0 or Β±2 with each operation
Why it matters: If you misunderstand this, you might think you can always make all elements positive, which is incorrect when starting with an odd number of negative elements.
Solution: Remember that each operation affects exactly two elements. This is why parity (odd/even count) of negative numbers is the key insight.
2. Incorrect Calculation When One Element Must Remain Negative
Pitfall: When an odd number of negatives exists, developers often make errors in the final calculation:
# Wrong approaches: return total_absolute_sum - min_absolute_value # Only subtracts once return total_absolute_sum + min_absolute_value # Adds instead of subtracts
Why it's wrong: When we compute total_absolute_sum
, we add the absolute value of ALL elements (including the one that will remain negative). To correct this:
- We need to remove the positive contribution:
-min_absolute_value
- We need to add the negative contribution:
-min_absolute_value
- Total adjustment:
-2 * min_absolute_value
Solution: Always use total_absolute_sum - 2 * min_absolute_value
for the odd case.
3. Not Considering Zero Values
Pitfall: Forgetting that zero values can exist in the matrix and not handling them properly when tracking the minimum absolute value.
Why it matters: If the matrix contains zeros and you have an odd number of negative values, you can always choose to "keep" a zero as your "negative" element (since -0 = 0), resulting in no loss to your sum.
Solution: The code correctly handles this because:
abs(0) = 0
will become the minimum absolute value- When odd negatives exist:
total_absolute_sum - 2 * 0 = total_absolute_sum
- This naturally gives the optimal result
4. Integer Overflow in Large Matrices
Pitfall: For very large matrices with large values, the sum might exceed standard integer limits in some languages.
Solution: In Python, this isn't an issue due to arbitrary precision integers. In other languages like Java or C++, consider using long
or long long
data types:
long totalSum = 0; // Use long instead of int
5. Inefficient Minimum Tracking Initialization
Pitfall: Initializing the minimum absolute value incorrectly:
# Wrong: might miss actual minimum if all values are large min_absolute_value = 0 # Wrong: might cause issues if matrix is empty min_absolute_value = matrix[0][0]
Solution: Initialize with float('inf')
to ensure any actual value will be smaller, and the min() function will work correctly on the first comparison.
Which of the following array represent a max heap?
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Donβt Miss This!