二维前缀和是一维前缀和的扩展,思维较简单;但由于码量和思维都需要仔细,因此不如做个模板直接调用完事。
用O(mn)的时间预处理,O(1)时间查询一块矩形面积的和。
例题: 304. 二维区域和检索 - 矩阵不可变
二维前缀和模板
class PreSum2d:
# 二维前缀和(支持加法和异或),只能离线使用,用n*m时间预处理,用O1查询子矩阵的和;op=0是加法,op=1是异或
def __init__(self,g,op=0):
m,n = len(g),len(g[0])
self.op = op
self.p=p=[[0]*(n+1) for _ in range(m+1)]
if op == 0:
for i in range(m):
for j in range(n):
p[i+1][j+1] = p[i][j+1]+p[i+1][j]-p[i][j]+g[i][j]
elif op==1:
for i in range(m):
for j in range(n):
p[i+1][j+1] = p[i][j+1]^p[i+1][j]^p[i][j]^g[i][j]
# O(1)时间查询闭区间左上(a,b),右下(c,d)矩形部分的数字和。
def sum_square(self,a,b,c,d):
if self.op == 0:
return self.p[c+1][d+1]+self.p[a][b]-self.p[a][d+1]-self.p[c+1][b]
elif self.op==1:
return self.p[c+1][d+1]^self.p[a][b]^self.p[a][d+1]^self.p[c+1][b]
class NumMatrix:
def __init__(self, mat: List[List[int]]):
self.pre = PreSum2d(mat)
def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int:
# pre = self.pre
return self.pre.sum_square(row1,col1,row2,col2)
链接: 1738. 找出第 K 大的异或坐标值
真-求左上角矩形的异或和。
class PreSum2d:
# 二维前缀和(支持加法和异或),只能离线使用,用n*m时间预处理,用O1查询子矩阵的和;op=0是加法,op=1是异或
def __init__(self,g,op=0):
m,n = len(g),len(g[0])
self.op = op
self.p=p=[[0]*(n+1) for _ in range(m+1)]
if op == 0:
for i in range(m):
for j in range(n):
p[i+1][j+1] = p[i][j+1]+p[i+1][j]-p[i][j]+g[i][j]
elif op==1:
for i in range(m):
for j in range(n):
p[i+1][j+1] = p[i][j+1]^p[i+1][j]^p[i][j]^g[i][j]
# O(1)时间查询闭区间左上(a,b),右下(c,d)矩形部分的数字和。
def sum_square(self,a,b,c,d):
if self.op == 0:
return self.p[c+1][d+1]+self.p[a][b]-self.p[a][d+1]-self.p[c+1][b]
elif self.op==1:
return self.p[c+1][d+1]^self.p[a][b]^self.p[a][d+1]^self.p[c+1][b]
# 这个也能用,常数小一丢丢
def xor_square(self,a,b,c,d):
return self.p[c+1][d+1]^self.p[a][b]^self.p[a][d+1]^self.p[c+1][b]
class Solution:
def kthLargestValue(self, matrix: List[List[int]], k: int) -> int:
m,n = len(matrix),len(matrix[0])
pre = PreSum2d(matrix,op=1)
ans = []
for i in range(m):
for j in range(n):
ans.append(pre.xor_square(0,0,i,j))
# print(ans)
return sorted(ans,reverse=True)[k-1]
链接: 2428. 沙漏的最大总和
这题可以暴力,用一下模板试试
class PreSum2d:
# 二维前缀和(支持加法和异或),只能离线使用,用n*m时间预处理,用O1查询子矩阵的和;op=0是加法,op=1是异或
def __init__(self,g,op=0):
m,n = len(g),len(g[0])
self.op = op
self.p=p=[[0]*(n+1) for _ in range(m+1)]
if op == 0:
for i in range(m):
for j in range(n):
p[i+1][j+1] = p[i][j+1]+p[i+1][j]-p[i][j]+g[i][j]
elif op==1:
for i in range(m):
for j in range(n):
p[i+1][j+1] = p[i][j+1]^p[i+1][j]^p[i][j]^g[i][j]
# O(1)时间查询闭区间左上(a,b),右下(c,d)矩形部分的数字和。
def sum_square(self,a,b,c,d):
if self.op == 0:
return self.p[c+1][d+1]+self.p[a][b]-self.p[a][d+1]-self.p[c+1][b]
elif self.op==1:
return self.p[c+1][d+1]^self.p[a][b]^self.p[a][d+1]^self.p[c+1][b]
class Solution:
def maxSum(self, grid: List[List[int]]) -> int:
pre = PreSum2d(grid)
ans = 0
m,n = len(grid),len(grid[0])
for i in range(m-2):
for j in range(n-2):
ans = max(ans, pre.sum_square(i,j,i+2,j+2) - grid[i+1][j]-grid[i+1][j+2])
return ans