【1252. 奇数值单元格的数目】

这篇博客介绍了如何高效地计算一个二维矩阵在一系列增量操作后包含的奇数单元格数量。提供了三种不同的C++实现方法,包括直接模拟、空间优化和计数优化,最后一种方法在时间和空间复杂度上都有所优化,并在LeetCode平台上达到了最佳性能。这些方法通过统计行和列的增大量,避免了不必要的矩阵遍历,实现了高效的求解策略。
摘要由CSDN通过智能技术生成

来源:力扣(LeetCode)

描述:

给你一个 m x n 的矩阵,最开始的时候,每个单元格中的值都是 0

另有一个二维索引数组 indicesindices[i] = [ri, ci] 指向矩阵中的某个位置,其中 rici 分别表示指定的行和列(从 0 开始编号)。

indices[i] 所指向的每个位置,应同时执行下述增量操作:

  1. ri 行上的所有单元格,加 1 。

  2. ci 列上的所有单元格,加 1 。

给你 mnindices 。请你在执行完所有 indices 指定的增量操作后,返回矩阵中 奇数值单元格 的数目。

示例 1:
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:

2

输入:m = 2, n = 2, indices = [[1,1],[0,0]]
输出:0
解释:最后的矩阵是 [[2,2],[2,2]],里面没有奇数。

提示:

  • 1 <= m, n <= 50
  • 1 <= indices.length <= 100
  • 0 <= ri < m
  • 0 <= ci < n

方法一:直接模拟

直接使用使用一个 n × m 的矩阵来存放操作的结果,对于 indices 中的每一对 [ri, ci],将矩阵第 ri 行的所有数增加 1,第 ci 列的所有数增加 1。在所有操作模拟完毕后,我们遍历矩阵,得到奇数的数目。

代码:

class Solution {
public:
    int oddCells(int m, int n, vector<vector<int>>& indices) {
        int res = 0;
        vector<vector<int>> matrix(m, vector<int>(n));
        for (auto &index : indices) {
            for (int i = 0; i < n; i++) {
                matrix[index[0]][i]++;
            }
            for (int i = 0; i < m; i++) {
                matrix[i][index[1]]++;
            }
        }
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] & 1) {
                    res++;
                }
            }
        }
        return res;
    }
};

执行用时:4 ms, 在所有 C++ 提交中击败了71.37%的用户
内存消耗:7.9 MB, 在所有 C++ 提交中击败了16.94%的用户
复杂度分析
时间复杂度: O(q × (m+n) + m×n), 其中 q 表示数组 indices 的长度,m, n 为矩阵的行数与列数。遍历数组时,每次都需要更新矩阵中一行加一列,需要的时间为 O(q×(m+n)),最后还需要遍历矩阵,需要的时间为 O(m×n),总的时间复杂度为 O(q×(m+n)+m×n)。
空间复杂度: O(m×n),其中 m, n 为矩阵的行数与列数。需要存储矩阵的所有元素。

方法二:模拟空间优化

由于每次操作只会将一行和一列的数增加 1,因此我们可以使用一个行数组 rows 和列数组 cols 分别记录每一行和每一列被增加的次数。对于 indices 中的每一对 [ri, ci],我们将rows[ri]cols[ci] 的值分别增加 1

在所有操作完成后,我们可以计算出位置 (x, y) 位置的计数即为 rows[x] + cols[y]。遍历矩阵,即可得到所有奇数的数目。

代码:

class Solution {
public:
    int oddCells(int m, int n, vector<vector<int>>& indices) {
        vector<int> rows(m), cols(n);
        for (auto & index : indices) {
            rows[index[0]]++;
            cols[index[1]]++;
        }
        int res = 0;
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if ((rows[i] + cols[j]) & 1) {
                    res++;
                }
            }
        }
        return res;
    }
};

执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:7.6 MB, 在所有 C++ 提交中击败了59.27%的用户
复杂度分析
时间复杂度: O(q + m × n), 其中 q 表示数组 indices 的长度,m, n 为矩阵的行数与列数。遍历数组时需要的时间为 O(q),最后还需要遍历矩阵,需要的时间为 O(m×n),因此总的时间复杂度为 O(q + m × n)。
空间复杂度:O(m + n) ,其中 m, n 为矩阵的行数与列数。需要存储矩阵的行数统计与列数统计。

方法三:计数优化

继续对方法二进行优化,矩阵中位于 (x, y) 位置的数为奇数,当且仅当 rows[x]cols[y] 中恰好有一个为奇数,一个为偶数。设 rowsoddx 个奇数colsoddy 个奇数,因此对于 rows[x] 为偶数,那么在第 x 行有 oddy 个位置的数为奇数;对于rows[x] 为奇数,那么在第 x 行有 m − oddy 个位置的数为偶数。综上我们可以得到奇数的数目为 oddx × (n−oddy) + (m−oddx) × oddy

代码:

class Solution {
public:
    int oddCells(int m, int n, vector<vector<int>>& indices) {
        vector<int> rows(m), cols(n);
        for (auto & index : indices) {
            rows[index[0]]++;
            cols[index[1]]++;
        }
        int oddx = 0, oddy = 0;
        for (int i = 0; i < m; i++) {
            if (rows[i] & 1) {
                oddx++;
            }
        }
        for (int i = 0; i < n; i++) {
            if (cols[i] & 1) {
                oddy++;
            }
        }
        return oddx * (n - oddy) + (m - oddx) * oddy;
    }
};

执行用时:0 ms, 在所有 C++ 提交中击败了100.00%的用户
内存消耗:7.5 MB, 在所有 C++ 提交中击败了82.26%的用户
复杂度分析
时间复杂度:O(q + m + n) , 其中 q 表示数组 indices 的长度,m, n 为矩阵的行数与列数。
空间复杂度:O(m + n) ,其中 m, n 为矩阵的行数与列数。需要存储矩阵的行数统计与列数统计。
author:LeetCode-Solution

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千北@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值