[python刷题模板] 二维前缀和

[python刷题模板] 二维前缀和

    • 一、 算法&数据结构
      • 1. 描述
      • 2. 复杂度分析
      • 3. 常见应用
      • 4. 常用优化
    • 二、 模板代码
      • 1. 预处理+询问,模板题。
      • 2. 二维前缀异或和
      • 3. 矩形抠掉两个点。
    • 三、其他
    • 四、更多例题
    • 五、参考链接

一、 算法&数据结构

1. 描述

二维前缀和是一维前缀和的扩展,思维较简单;但由于码量和思维都需要仔细,因此不如做个模板直接调用完事。
用O(mn)的时间预处理,O(1)时间查询一块矩形面积的和。

2. 复杂度分析

  1. 预处理, O(M×N)
  2. 查询,O(1)

3. 常见应用

  1. 求矩阵区域和。

4. 常用优化

二、 模板代码

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)

2. 二维前缀异或和

链接: 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]

3. 矩形抠掉两个点。

链接: 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

三、其他

  1. 由于查询需要function call,肯定会常数大一些

四、更多例题

五、参考链接

你可能感兴趣的:(python刷题模板,leetcode,python,算法)