📜  在 Q 查询的给定范围内翻转子矩阵后的二进制矩阵(1)

📅  最后修改于: 2023-12-03 15:07:47.425000             🧑  作者: Mango

在 Q 查询的给定范围内翻转子矩阵后的二进制矩阵

问题描述

给定一个大小为 $n \times m$ 的二进制矩阵 $mat$,以及一些查询操作,每个查询操作都表示在 $mat$ 中选中一些单元格,并将选中的单元格中的值全部取反(如果原来是 $0$ 则变为 $1$,如果原来是 $1$ 则变为 $0$)。请你返回经过所有查询操作之后,矩阵中的元素个数等于 $1$ 的单元格的个数。

解法

我们可以使用暴力算法来模拟这个过程,依次处理每个查询,然后统计单元格中的 $1$ 的个数即可。时间复杂度为 $O(qnm)$,其中 $q$ 表示查询的次数,$n$ 和 $m$ 分别是矩阵的行数和列数。

更高效的解法是使用前缀和,可以将每个单元格中 $1$ 的个数记录下来,然后在每个查询操作中将涉及到的单元格中的 $1$ 的个数分别取反(这个过程可以使用前缀和优化),最后在矩阵中统计 $1$ 的个数即可。时间复杂度为 $O(q(n+m))$。

具体实现可以参考以下代码(假设所有坐标从 $1$ 开始编号,$mat_{i,j}$ 表示第 $i$ 行第 $j$ 列的元素,$cnt_{i,j}$ 表示以 $(i,j)$ 为右下角的子矩阵中 $1$ 的个数):

def get_count(i, j):
    return cnt[i][j] - cnt[i-1][j] - cnt[i][j-1] + cnt[i-1][j-1]

for k in range(q):
    x1, y1, x2, y2 = queries[k]
    for i in range(x1, x2+1):
        for j in range(y1, y2+1):
            cnt[i][j] = 1 - cnt[i][j]
            mat[i][j] = 1 - mat[i][j]
            if i > 1:
                cnt[i][j] += cnt[i-1][j]
            if j > 1:
                cnt[i][j] += cnt[i][j-1]
            if i > 1 and j > 1:
                cnt[i][j] -= cnt[i-1][j-1]

ans = 0
for i in range(1, n+1):
    for j in range(1, m+1):
        if mat[i][j] == 1 and get_count(i, j) == 1:
            ans += 1

return ans

这段代码中使用了前缀和来实现矩阵中单元格中 $1$ 的个数的快速统计,时间复杂度为 $O(nm)$。在处理每个查询操作时,我们依次将涉及到的单元格中的 $1$ 的个数取反,复杂度为 $O(q(n+m))$。最后统计 $1$ 的个数时,我们只需要判断单元格中的值是否为 $1$,以及以该单元格为右下角的子矩阵中 $1$ 的个数是否为 $1$ 即可完成判断,时间复杂度是 $O(nm)$。因为 $q$ 往往较小,所以总的时间复杂度可以看作是线性的。

参考链接