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

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

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

在一个给定的二维二进制矩阵中,每个元素的值要么是 0 要么是 1。

我们设计一个查询操作求出在矩形 (top_left, bottom_right) 范围内的所有元素的和,并将这个矩形中的每个元素进行取反操作。具体来说,对于矩形中的每个元素,将其从 0 变成 1,或者从 1 变成 0。

给定一个初始值全部为 0 的二维矩阵,你需要执行若干次查询操作,最终得到经过多次查询操作后,矩阵中每个元素的值。

方法

我们可以考虑使用矩阵前缀和,先通过前缀和计算出每个点的值,然后再进行取反操作。

对于 top_left 和 bottom_right,我们可以分别用 (i,j) 和 (x,y) 表示,我们可以得到以下的式子:

$$\text{sum}(i,j,x,y) = \text{sum}(0,0,x,y) - \text{sum}(0,0,i-1,y) - \text{sum}(0,0,x,j-1) + \text{sum}(0,0,i-1,j-1)$$

其中,$\text{sum}(i,j,x,y)$ 表示从左上角为 $(1,1)$,右下角为 $(x,y)$ 的子矩阵的和,同时如果我们对这个子矩阵进行取反操作,那么得到的新的子矩阵范围就是 $\text{sum}(i,j,x,y) - \text{sum}(i,j,x,y)$,也就是利用差分的思想,对取反操作进行优化。

同时我们还可以将一个二进制矩阵压缩为一个一维数组,其中第 $i$ 列的第 $j$ 行的数值可以表示为 $M[i*col+j]$,其中 $col$ 表示列数。

最终的代码为:

class BinaryMatrix:
    def __init__(self, matrix):
        self.matrix = matrix
        self.sums = [self._build_sum(row) for row in matrix]
        
    def _build_sum(self, row):
        cur_sum = 0
        result = []
        for val in row:
            cur_sum += val
            result.append(cur_sum)
        return result

    def get(self, x: int, y: int) -> int:
        return self.matrix[x][y]

    def dimensions(self) -> List[int]:
        return [len(self.matrix), len(self.matrix[0])]
    

class Solution:
    def construct(self, matrix: List[List[int]]) -> 'BinaryMatrix':
        return BinaryMatrix(matrix)

    def flipAndInvertImage(self, A: List[List[int]]) -> List[List[int]]:
        binary_matrix = self.construct(A)
        rows, cols = binary_matrix.dimensions()
        
        for i in range(rows):
            for j in range(cols // 2):
                binary_matrix.matrix[i][j], binary_matrix.matrix[i][cols - 1 - j] = binary_matrix.matrix[i][cols - 1 - j], binary_matrix.matrix[i][j]

        result = []
        for i in range(rows):
            row = []
            for j in range(cols):
                row.append(int(not binary_matrix.get(i, j)))
            result.append(row)

        return result

    def search(self, reader: 'ArrayReader', target: int) -> int:
        max_val = 10000
        
        while reader.get(0) < max_val and reader.get(1) < target:
            max_val *= 2

        left, right = 0, max_val
        
        while left < right:
            mid = (left + right) // 2
            
            if reader.get(mid) >= target:
                right = mid
            else:
                left = mid + 1
                
        if reader.get(left) == target:
            return left
        else:
            return -1
            
    def matrixBlockSum(self, mat: List[List[int]], K: int) -> List[List[int]]:
        binary_matrix = self.construct(mat)
        rows, cols = binary_matrix.dimensions()
        
        for i in range(rows):
            for j in range(cols):
                val = binary_matrix.get(i, j)
                binary_matrix.matrix[i][j] = val * (1 - 2 * ((i + j) % 2))

        for i in range(rows):
            for j in range(cols):
                binary_matrix.matrix[i][j] += binary_matrix.get(i - 1, j) + binary_matrix.get(i, j - 1) - binary_matrix.get(i - 1, j - 1)
        
        result = [[0] * cols for _ in range(rows)]
        for i in range(rows):
            for j in range(cols):
                r_start = max(0, i - K)
                r_end = min(rows - 1, i + K)
                c_start = max(0, j - K)
                c_end = min(cols - 1, j + K)
                
                result[i][j] = binary_matrix.get(r_end, c_end) - binary_matrix.get(r_end, c_start - 1) - binary_matrix.get(r_start - 1, c_end) + binary_matrix.get(r_start - 1, c_start - 1)
                
        return result

其中,construct 函数构建了一个 BinaryMatrix 类,该类可以对二维矩阵进行取反和前缀和的操作,同时可以直接通过 get 函数获取元素值和 dimensions 函数获取矩阵的行数和列数。

flipAndInvertImage 函数对二进制矩阵进行操作,先对每一行进行翻转操作再进行取反操作,得到新的二进制矩阵。

search 函数则是对一个有序数组进行二分搜索,找到等于给定值的元素。

最终的 matrixBlockSum 函数则是利用前缀和和差分的思想计算矩形范围内元素的和,并对每个元素进行取反操作。函数首先计算出每个元素在取反操作之前的值,然后再利用前缀和计算出每个点在取反操作之后的值,最后对矩形范围内的元素进行求和即可。