Medium
题目描述
给你一个下标从 0 开始的 m x n 二进制矩阵 grid。
我们按照如下过程,创建一个下标从 0 开始的 m x n 差值矩阵 diff:
- 令第
i行一的数目为onesRowi。 - 令第
j列一的数目为onesColj。 - 令第
i行零的数目为zerosRowi。 - 令第
j列零的数目为zerosColj。 diff[i][j] = onesRowi + onesColj - zerosRowi - zerosColj
请你返回差值矩阵 diff 。
示例 1:
输入:grid = [[0,1,1],[1,0,1],[0,0,1]]
输出:[[0,0,4],[0,0,4],[-2,-2,2]]
解释:
- diff[0][0] = onesRow0 + onesCol0 - zerosRow0 - zerosCol0 = 2 + 1 - 1 - 2 = 0
- diff[0][1] = onesRow0 + onesCol1 - zerosRow0 - zerosCol1 = 2 + 1 - 1 - 2 = 0
- diff[0][2] = onesRow0 + onesCol2 - zerosRow0 - zerosCol2 = 2 + 3 - 1 - 0 = 4
- diff[1][0] = onesRow1 + onesCol0 - zerosRow1 - zerosCol0 = 2 + 1 - 1 - 2 = 0
- diff[1][1] = onesRow1 + onesCol1 - zerosRow1 - zerosCol1 = 2 + 1 - 1 - 2 = 0
- diff[1][2] = onesRow1 + onesCol2 - zerosRow1 - zerosCol2 = 2 + 3 - 1 - 0 = 4
- diff[2][0] = onesRow2 + onesCol0 - zerosRow2 - zerosCol0 = 1 + 1 - 2 - 2 = -2
- diff[2][1] = onesRow2 + onesCol1 - zerosRow2 - zerosCol1 = 1 + 1 - 2 - 2 = -2
- diff[2][2] = onesRow2 + onesCol2 - zerosRow2 - zerosCol2 = 1 + 3 - 2 - 0 = 2
示例 2:
输入:grid = [[1,1,1],[1,1,1]]
输出:[[5,5,5],[5,5,5]]
提示:
m == grid.lengthn == grid[i].length1 <= m, n <= 10^51 <= m * n <= 10^5grid[i][j]不是0就是1
解题思路
解题思路
这道题的核心是理解差值矩阵的计算公式:diff[i][j] = onesRowi + onesColj - zerosRowi - zerosColj
思路分析
预处理优化:题目提示我们要重复使用行和列的信息,所以应该先预计算每行和每列的1的个数,避免重复计算。
数学化简:注意到对于第i行,
zerosRowi = n - onesRowi(总列数减去1的个数);对于第j列,zerosColj = m - onesColj(总行数减去1的个数)。公式推导:
diff[i][j] = onesRowi + onesColj - zerosRowi - zerosColj = onesRowi + onesColj - (n - onesRowi) - (m - onesColj) = 2 * onesRowi + 2 * onesColj - n - m算法步骤:
- 第一次遍历:统计每行的1的个数
- 第二次遍历:统计每列的1的个数
- 第三次遍历:根据简化公式计算差值矩阵
这种预处理方法避免了对每个位置重复计算行列统计,时间复杂度从O(m²n²)优化到O(mn)。
代码实现
class Solution {
public:
vector<vector<int>> onesMinusZeros(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size();
// 统计每行的1的个数
vector<int> onesRow(m, 0);
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
onesRow[i] += grid[i][j];
}
}
// 统计每列的1的个数
vector<int> onesCol(n, 0);
for (int j = 0; j < n; j++) {
for (int i = 0; i < m; i++) {
onesCol[j] += grid[i][j];
}
}
// 计算差值矩阵
vector<vector<int>> diff(m, vector<int>(n));
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
diff[i][j] = 2 * onesRow[i] + 2 * onesCol[j] - m - n;
}
}
return diff;
}
};
class Solution:
def onesMinusZeros(self, grid: List[List[int]]) -> List[List[int]]:
m, n = len(grid), len(grid[0])
# 统计每行的1的个数
ones_row = [sum(row) for row in grid]
# 统计每列的1的个数
ones_col = [sum(grid[i][j] for i in range(m)) for j in range(n)]
# 计算差值矩阵
diff = [[2 * ones_row[i] + 2 * ones_col[j] - m - n
for j in range(n)] for i in range(m)]
return diff
public class Solution {
public int[][] OnesMinusZeros(int[][] grid) {
int m = grid.Length, n = grid[0].Length;
// 统计每行的1的个数
int[] onesRow = new int[m];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
onesRow[i] += grid[i][j];
}
}
// 统计每列的1的个数
int[] onesCol = new int[n];
for (int j = 0; j < n; j++) {
for (int i = 0; i < m; i++) {
onesCol[j] += grid[i][j];
}
}
// 计算差值矩阵
int[][] diff = new int[m][];
for (int i = 0; i < m; i++) {
diff[i] = new int[n];
for (int j = 0; j < n; j++) {
diff[i][j] = 2 * onesRow[i] + 2 * onesCol[j] - m - n;
}
}
return diff;
}
}
/**
* @param {number[][]} grid
* @return {number[][]}
*/
var onesMinusZeros = function(grid) {
const m = grid.length, n = grid[0].length;
// 统计每行的1的个数
const onesRow = new Array(m).fill(0);
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
onesRow[i] += grid[i][j];
}
}
// 统计每列的1的个数
const onesCol = new Array(n).fill(0);
for (let j = 0; j < n; j++) {
for (let i = 0; i < m; i++) {
onesCol[j] += grid[i][j];
}
}
// 计算差值矩阵
const diff = new Array(m).fill().map(() => new Array(n));
for (let i = 0; i < m; i++) {
for (let j = 0; j < n; j++) {
diff[i][j] = 2 * onesRow[i] + 2 * onesCol[j] - m - n;
}
}
return diff;
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(m × n) | 需要遍历整个矩阵三次:统计行、统计列、计算结果 |
| 空间复杂度 | O(m + n) | 需要额外的数组存储每行和每列的1的个数,不包括结果矩阵的空间 |
相关题目
. 01 Matrix (Medium)