题目描述
(简单)给你一个 m x n
的矩阵,最开始的时候,每个单元格中的值都是 0
。
另有一个二维索引数组 indices
,indices[i] = [ri, ci]
指向矩阵中的某个位置,其中 ri
和 ci
分别表示指定的行和列(从 0
开始编号)。
对 indices[i]
所指向的每个位置,应同时执行下述增量操作:
ri
行上的所有单元格,加1
。ci
列上的所有单元格,加1
。
给你 m
、n
和 indices
。请你在执行完所有 indices
指定的增量操作后,返回矩阵中奇数值单元格的数目。
示例:
输入:m = 2, n = 3, indices = [[0,1],[1,1]]
输出:6
解释:最开始的矩阵是 [[0,0,0],[0,0,0]]。
第一次增量操作后得到 [[1,2,1],[0,1,0]]。
最后的矩阵是 [[1,3,1],[1,3,1]],里面有 6 个奇数。
解题思路
之所以是简单题,是因为暴力模拟不会超时。。。但模拟的时间、空间复杂度实在是太高了,故考虑其他算法优化一下。
本体有如下特点:
- 每次修改是以行、列为单位;
- 单考虑行,每次修改答案增加列数个;
- 单考虑列,每次修改答案增加行数个;
- 无论是整行、整列或者单个矩阵元素,偶数次修改等价于无改动;
因此,首先考虑的就是将耦合在 indices[]
的操作解耦。分别记录各行各列的修改次数,奇数次维护答案,偶数次跳过。
需要考虑的一点是,若先考虑行,当再考虑列时,列的修改是不再是单纯增加行数。将行、列解耦的好处是,行操作完后矩阵关于列是统一的。因此,后续进行列操作时,每列的改动值时固定的。
- 假设列操作前,每列奇数单元有
c
个; - 考虑操作性质后,改动后的技术单元个数为
m - c
; - 因此,每次列操作后,奇数单元增量为
m - 2c
;
代码实现
class Solution {
public:
int oddCells(int m, int n, vector<vector<int>>& indices) {
//维护各行访问次数
vector<int> row(m);
//维护各列访问次数
vector<int> col(n);
for(auto& vec : indices){
row[vec[0]]++;
col[vec[1]]++;
}
int res = 0;
//奇数的行数
int cnt = 0;
//每一奇数行增加n个
for(int& i :row){
if(i & 1){
cnt++;
res += n;
}
}
for(int& i :col){
if(i & 1){
//每访问一列增加量 m - 2 * cnt
res += (m - 2 * cnt);
}
}
return res;
}
};
运行结果: