携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情
每日刷题 2022.08.06
- leetcode原题链接:leetcode.cn/problems/ce…
- 难度:简单
- 方法:数学
题目
- 给你一个 m x n 的矩阵,最开始的时候,每个单元格中的值都是 0。
- 另有一个二维索引数组 indices,indices[i] = [ri, ci] 指向矩阵中的某个位置,其中 ri 和 ci 分别表示指定的行和列(从 0 开始编号)。
- 对 indices[i] 所指向的每个位置,应同时执行下述增量操作:
- ri 行上的所有单元格,加 1 。
- ci 列上的所有单元格,加 1 。
- 给你 m、n 和 indices 。请你在执行完所有 indices 指定的增量操作后,返回矩阵中 奇数值单元格 的数目。
示例
- 示例1
输入: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 个奇数。
- 示例2
输入: m = 2, n = 2, indices = [[1,1],[0,0]]
输出: 0
解释: 最后的矩阵是 [[2,2],[2,2]],里面没有奇数。
提示
1 <= m, n <= 501 <= indices.length <= 1000 <= ri < m0 <= ci < n
进阶
- 你可以设计一个时间复杂度为
O(n + m + indices.length)且仅用O(n + m)额外空间的算法来解决此问题吗?
解题思路
- 因为题目的数据范围并不是很大,所以直接暴力模拟就可以实现。
- 除了暴力模拟以外的其他的方法讲解:
- 方法一:对于矩阵中的每一个格子中的元素,都有一个属于自己的行和列号,因此只需要分别记录其所在的行号和列号每次被加的次数,最终将每一个格子的行号和列号相加,如果是奇数,那么就需要记录。这种方法相较于直接暴力模拟的方法,节省了空间,直接使用两个一维数组来分别记录行号和列号即可。
- 方法二:首先需要统计每一行和每一列都被加了多少次,然后从中计算出被加了奇数次的行数和列数。
- 那么使用容斥原理可知:每一行会有
n个数变成奇数,每一列会有m个数会变成奇数,这样的话每一个行和列的交点都是偶数(不符合题意)。因此需要给每一个奇数行配上偶数列,每一个偶数行配上奇数列。 - 奇数加奇数一定是偶数;奇数加偶数一定是奇数
- 那么使用容斥原理可知:每一行会有
AC代码
- 方法一
/**
* @param {number} m
* @param {number} n
* @param {number[][]} indices
* @return {number}
*/
var oddCells = function(m, n, indices) {
// 因为不需要知道每一个到底是什么值,因此也不用完全暴力模拟
// 因为在前面的方法上,可以进阶到下述的方法
// 因为每个左边上的值,就是当前的行和列相加
let row = new Array(m).fill(0), col = new Array(n).fill(0);
for(let one of indices) {
row[one[0]]++;
col[one[1]]++;
}
let ans = 0;
for(let i = 0; i < m; i++) {
for(let j = 0; j < n; j++) {
if((row[i] + col[j]) & 1) ans++;
}
}
return ans;
};
- 方法二
/**
* @param {number} m
* @param {number} n
* @param {number[][]} indices
* @return {number}
*/
var oddCells = function(m, n, indices) {
// 还可以再优化,通过分析后,解决全部遍历一遍,挨个判断其是否为奇数的方法
// 奇数的总次数 = 横奇数 + 列偶数 或者 横偶数 + 列奇数
let row = new Array(m).fill(0), col = new Array(n).fill(0);
for(let one of indices) {
row[one[0]]++;
col[one[1]]++;
}
let oddR = 0, oddL = 0;
for(let r of row) {
if(r & 1) oddR++;
}
for(let c of col) {
if(c & 1) oddL++;
}
return oddR * (n - oddL) + (m - oddR) * oddL;
};