📅  最后修改于: 2023-12-03 15:07:56.291000             🧑  作者: Mango
在一个给定的二维二进制矩阵中,每个元素的值要么是 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
函数则是利用前缀和和差分的思想计算矩形范围内元素的和,并对每个元素进行取反操作。函数首先计算出每个元素在取反操作之前的值,然后再利用前缀和计算出每个点在取反操作之后的值,最后对矩形范围内的元素进行求和即可。