Given a square matrix mat[][] of size n x n, return the minimum number of operations required to make the sum of elements in each row and each column equal. In one operation, you are allowed to increment any individual cell by 1.
Examples:Â
Input: mat[][] = [[1, 2], [3, 4]]
Output: 4
Explanation: Increment value of cell (0, 0) 3 times.Â
Increment value of cell (0, 1) 1 time.
Matrix after the operations: [[4, 3], [3, 4]]
with sum of each row and column as 7. Hence total 4 operation are required.Input: mat[][] = [[1, 2, 3], [4, 2, 3], [3, 2, 1]]
Output: 6
Explanation: Increment value of cell(0, 0) 1 time.Â
Increment value of cell(0, 1) 2 times.Â
Increment value of cell(2, 1) 1 time.
Increment value of cell(2, 2) 2 times.
Matrix after the operations: [[2, 4, 3], [4, 2, 3], [3, 3, 3]]
with sum of each row and column as 9. Hence total 6 operation are required.
Table of Content
[Naive Approach] Brute Force Simulation
The naive approach incrementally adjusts the matrix by always increasing the element at the intersection of the row and column with the minimum sums. This is repeated until all row and column sums become equal. It simulates the process step-by-step without optimization, leading to high time complexity.
Why it works:
- The only way to increase both row and column sums simultaneously is to increment a single cell.
- Since each increment increases one row and one column by 1, the most efficient strategy is to increase the lowest row and column simultaneously.
- This greedy method ensures you're always choosing the best possible cell to move the whole matrix closer to a balanced state in each step.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int balanceSums(vector<vector<int>>& mat) {
int n = mat.size();
vector<int> rowSum(n, 0), colSum(n, 0);
// Compute initial row and column sums
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j) {
rowSum[i] += mat[i][j];
colSum[j] += mat[i][j];
}
int op = 0;
// Repeat until all row and
// column sums become equal
while (true) {
// Find maximum row/col sum
int maxSum = *max_element(rowSum.begin(),
rowSum.end());
maxSum = max(maxSum, *max_element(colSum.begin(),
colSum.end()));
bool done = true;
for (int i = 0; i < n && done; ++i)
if (rowSum[i] != maxSum || colSum[i] != maxSum)
done = false;
if (done) break;
// Find row and column with the minimum sum
int minRow = min_element(rowSum.begin(),
rowSum.end()) - rowSum.begin();
int minCol = min_element(colSum.begin(),
colSum.end()) - colSum.begin();
// Increment the element
// at their intersection
mat[minRow][minCol]++;
rowSum[minRow]++;
colSum[minCol]++;
op++;
}
return op;
}
int main() {
vector<vector<int>> mat = {
{1, 2, 3},
{4, 2, 3},
{3, 2, 1}
};
cout << balanceSums(mat) << endl;
return 0;
}
import java.util.Arrays;
public class Main {
public static int balanceSums(int[][] mat)
{
int n = mat.length;
int[] rowSum = new int[n], colSum = new int[n];
// Compute initial row and column sums
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j) {
rowSum[i] += mat[i][j];
colSum[j] += mat[i][j];
}
int op = 0;
// Repeat until all row and
// column sums become equal
while (true) {
int maxSum
= Arrays.stream(rowSum).max().getAsInt();
maxSum = Math.max(maxSum, Arrays.stream(colSum)
.max()
.getAsInt());
boolean done = true;
for (int i = 0; i < n && done; ++i)
if (rowSum[i] != maxSum
|| colSum[i] != maxSum)
done = false;
if (done)
break;
// Find row and column with the minimum sum
int minRow = 0;
for (int i = 1; i < n; ++i)
if (rowSum[i] < rowSum[minRow])
minRow = i;
int minCol = 0;
for (int i = 1; i < n; ++i)
if (colSum[i] < colSum[minCol])
minCol = i;
// Increment the element
// at their intersection
mat[minRow][minCol]++;
rowSum[minRow]++;
colSum[minCol]++;
op++;
}
return op;
}
public static void main(String[] args)
{
int[][] mat
= { { 1, 2, 3 }, { 4, 2, 3 }, { 3, 2, 1 } };
System.out.println(balanceSums(mat));
}
}
def balanceSums(mat):
n = len(mat)
rowSum = [0] * n
colSum = [0] * n
# Compute initial row and column sums
for i in range(n):
for j in range(n):
rowSum[i] += mat[i][j]
colSum[j] += mat[i][j]
op = 0
# Repeat until all row and
# column sums become equal
while True:
# Find maximum row/col sum
maxSum = max(rowSum)
maxSum = max(maxSum, max(colSum))
done = True
for i in range(n):
if rowSum[i] != maxSum or colSum[i] != maxSum:
done = False
if done:
break
# Find row and column with the minimum sum
minRow = rowSum.index(min(rowSum))
minCol = colSum.index(min(colSum))
# Increment the element
# at their intersection
mat[minRow][minCol] += 1
rowSum[minRow] += 1
colSum[minCol] += 1
op += 1
return op
if __name__ == '__main__':
mat = [
[1, 2, 3],
[4, 2, 3],
[3, 2, 1]
]
print(balanceSums(mat))
using System;
using System.Linq;
class GFG {
public int balanceSums(int[, ] mat)
{
int n = mat.GetLength(0);
int[] rowSum = new int[n];
int[] colSum = new int[n];
// Compute initial row and column sums
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j) {
rowSum[i] += mat[i, j];
colSum[j] += mat[i, j];
}
int op = 0;
// Repeat until all row and column sums become equal
while (true) {
// Find maximum row/col sum
int maxSum
= Math.Max(rowSum.Max(), colSum.Max());
bool done = true;
for (int i = 0; i < n && done; ++i)
if (rowSum[i] != maxSum
|| colSum[i] != maxSum)
done = false;
if (done)
break;
// Find row and column with the minimum sum
int minRow = 0, minCol = 0;
for (int i = 1; i < n; ++i)
if (rowSum[i] < rowSum[minRow])
minRow = i;
for (int j = 1; j < n; ++j)
if (colSum[j] < colSum[minCol])
minCol = j;
// Increment the element at their intersection
mat[minRow, minCol]++;
rowSum[minRow]++;
colSum[minCol]++;
op++;
}
return op;
}
public void Main()
{
int[, ] mat
= { { 1, 2, 3 }, { 4, 2, 3 }, { 3, 2, 1 } };
Console.WriteLine(balanceSums(mat));
}
}
function balanceSums(mat)
{
let n = mat.length;
let rowSum = new Array(n).fill(0);
let colSum = new Array(n).fill(0);
// Compute initial row and column sums
for (let i = 0; i < n; ++i)
for (let j = 0; j < n; ++j) {
rowSum[i] += mat[i][j];
colSum[j] += mat[i][j];
}
let op = 0;
// Repeat until all row and
// column sums become equal
while (true) {
// Find maximum row/col sum
let maxSum = Math.max(...rowSum);
maxSum = Math.max(maxSum, Math.max(...colSum));
let done = true;
for (let i = 0; i < n && done; ++i)
if (rowSum[i] != maxSum || colSum[i] != maxSum)
done = false;
if (done)
break;
// Find row and column with the minimum sum
let minRow = rowSum.indexOf(Math.min(...rowSum));
let minCol = colSum.indexOf(Math.min(...colSum));
// Increment the element
// at their intersection
mat[minRow][minCol]++;
rowSum[minRow]++;
colSum[minCol]++;
op++;
}
return op;
}
let mat = [ [ 1, 2, 3 ], [ 4, 2, 3 ], [ 3, 2, 1 ] ];
console.log(balanceSums(mat));
Output
6
Time Complexity: O(n2 * maxEleDiff) where maxEleDiff is the difference between the maximum and minimum sum values.
Auxiliary Space: O(n) for row and column sum arrays.
[Expected Approach] Max-Target Normalization - O(n^2) Time and O(1) Time
The idea is to equalize all row and column sums, so for that we will first compute: maxSum = max(maxRowSum, maxColSum). We aim to make every row and column sum equal to maxSum. To do this, we increment elements only in rows and columns that fall short of maxSum, ensuring we never exceed maxSum for any row or column. Each increment at a cell (i, j) contributes to both the row and column sums.
Why this approach works
- We only increase cells where both the row and column sums are less than maxSum .
- This ensures that no row or column ever exceeds the target sum.
- Every increment contributes to increasing the total matrix sum by 1.
- We stop once the total matrix sum reaches n × maxSum.
At this point:
- Each row sum ≤ maxSum, and total of all row sums = n × maxSum → so every row sum = maxSum.
- Same holds for columns.
Thus, all rows and columns are exactly maxSum, and we've used the minimum number of operations:
minOperations = n × s – totalSum
#include <iostream>
#include <vector>
using namespace std;
int balanceSums(vector<vector<int>> &mat) {
int n = mat.size();
int res = 0;
int maxSum = 0;
// find maximum sum across all rows
for(int i = 0; i < n; i++) {
int sum = 0;
for(int j = 0; j < n; j++)
sum += mat[i][j];
maxSum = max(sum, maxSum);
}
// find maximum sum across all columns
for(int j = 0; j < n; j++) {
int sum = 0;
for(int i = 0; i < n; i++)
sum += mat[i][j];
maxSum = max(sum, maxSum);
}
// sum of operations across all rows
for(int i = 0; i < n; i++) {
int sum = 0;
for(int j = 0; j < n; j++) {
sum += mat[i][j];
}
res += (maxSum - sum);
}
return res;
}
int main() {
vector<vector<int>> mat =
{
{ 1, 2, 3 },
{ 4, 2, 3 },
{ 3, 2, 1 }
};
cout << balanceSums(mat);
return 0;
}
import java.util.Arrays;
class GFG {
static int balanceSums(int[][] mat) {
int n = mat.length;
int res = 0;
int maxSum = 0;
// Find maximum sum across all rows
for (int i = 0; i < n; i++) {
int sum = 0;
for (int j = 0; j < n; j++) {
sum += mat[i][j];
}
maxSum = Math.max(sum, maxSum);
}
// Find maximum sum across all columns
for (int j = 0; j < n; j++) {
int sum = 0;
for (int i = 0; i < n; i++) {
sum += mat[i][j];
}
maxSum = Math.max(sum, maxSum);
}
// Sum of operations across all rows
for (int i = 0; i < n; i++) {
int sum = 0;
for (int j = 0; j < n; j++) {
sum += mat[i][j];
}
res += (maxSum - sum);
}
return res;
}
public static void main(String[] args) {
int[][] mat = {
{ 1, 2, 3 },
{ 4, 2, 3 },
{ 3, 2, 1 }
};
System.out.println(balanceSums(mat));
}
}
def balanceSums(mat):
n = len(mat)
res = 0
maxSum = 0
# Find maximum sum across all rows
for i in range(n):
sum = 0
for j in range(n):
sum += mat[i][j]
maxSum = max(sum, maxSum)
# Find maximum sum across all columns
for j in range(n):
sum = 0
for i in range(n):
sum += mat[i][j]
maxSum = max(sum, maxSum)
# Sum of operations across all rows
for i in range(n):
sum = 0
for j in range(n):
sum += mat[i][j]
res += (maxSum - sum)
return res
if __name__ == "__main__":
mat = [
[1, 2, 3],
[4, 2, 3],
[3, 2, 1]
]
print(balanceSums(mat))
using System;
using System.Collections.Generic;
class GFG {
public int balanceSums(int[,] mat) {
int n = mat.GetLength(0);
int res = 0;
int maxSum = 0;
// Find maximum sum across all rows
for (int i = 0; i < n; i++) {
int sum = 0;
for (int j = 0; j < n; j++)
sum += mat[i, j];
maxSum = Math.Max(sum, maxSum);
}
// Find maximum sum across all columns
for (int j = 0; j < n; j++) {
int sum = 0;
for (int i = 0; i < n; i++)
sum += mat[i, j];
maxSum = Math.Max(sum, maxSum);
}
// Sum of operations across all rows
for (int i = 0; i < n; i++) {
int sum = 0;
for (int j = 0; j < n; j++)
sum += mat[i, j];
res += (maxSum - sum);
}
return res;
}
public void Main(string[] args) {
int[,] mat = {
{ 1, 2, 3 },
{ 4, 2, 3 },
{ 3, 2, 1 }
};
Console.WriteLine(balanceSums(mat));
}
}
function balanceSums(mat) {
let n = mat.length;
let res = 0;
let maxSum = 0;
// Find maximum sum across all rows
for (let i = 0; i < n; i++) {
let sum = 0;
for (let j = 0; j < n; j++) {
sum += mat[i][j];
}
maxSum = Math.max(sum, maxSum);
}
// Find maximum sum across all columns
for (let j = 0; j < n; j++) {
let sum = 0;
for (let i = 0; i < n; i++) {
sum += mat[i][j];
}
maxSum = Math.max(sum, maxSum);
}
// Sum of operations across all rows
for (let i = 0; i < n; i++) {
let sum = 0;
for (let j = 0; j < n; j++) {
sum += mat[i][j];
}
res += (maxSum - sum);
}
return res;
}
// Driver Code
let mat = [
[ 1, 2, 3 ],
[ 4, 2, 3 ],
[ 3, 2, 1 ]
];
console.log(balanceSums(mat));
Output
6