前缀和与差分数组

前缀和应用场景:原始数组不会被修改的情况下,频繁查询某个区间的累加和。
eg:计算数组下标2到5的数组和,原本用for循环,有了前缀和直接用5的前缀和减去2的前缀和得到答案,可以将O(n)的复杂度降为O(1)

一维前缀和

  • 图解

preSum=[0]*(len(nums+1))#初始化前缀和数组,若nums是原数组
for i in range(1,len(preSum)):# 计算 nums 的累加和
    preSum[i]=preSum[i-1]+nums[i-1]#当前的前缀和等于前一个前缀和加上原数组的当前值(减一是因为索引移位了)

二维前缀和

  • 图解

  • 计算每个矩阵 [0, 0, i, j] 的元素和

# 定义:preSum[i][j] 记录 matrix 中子矩阵 [0, 0, i-1, j-1] 的元素和
    def __init__(self, matrix: List[List[int]]):
        m, n = len(matrix), len(matrix[0])
        if m == 0 or n == 0: return
        # 构造前缀和矩阵
        self.preSum = [[0 for _ in range(n+1)] for _ in range(m+1)]
        for i in range(1, m+1):
            for j in range(1, n+1):
                # 计算每个矩阵 [0, 0, i, j] 的元素和
                self.preSum[i][j] = self.preSum[i-1][j] + self.preSum[i][j-1] + matrix[i-1][j-1] - self.preSum[i-1][j-1]

差分数组

差分数组应用场景:频繁对原始数组的某个区间的元素进行增减。
eg:输入一个数组 nums,然后又要求给区间 nums[2..6] 全部加 1,再给 nums[3..9] 全部减 3,再给 nums[0..4] 全部加 2...求最后nums。解:构造差分数组=nums[i]
-nums[i-1],想对区间 nums[i..j] 的元素全部加 3,那么只需要让 diff[i] += 3,然后再让 diff[j+1] -= 3.详细解释如下

  • 图解:

diff = [0] * len(nums)
# 构造差分数组
diff[0] = nums[0]
for i in range(1, len(nums)):
    diff[i] = nums[i] - nums[i - 1]

差分数组反推出原始数组

res = [0] * len(diff)
# 根据差分数组构造结果数组
res[0] = diff[0]
for i in range(1, len(diff)):
    res[i] = res[i - 1] + diff[i]
  • 对区间 nums[i..j] 的元素全部加 3,那么只需要让 diff[i] += 3,然后再让 diff[j+1] -= 3,详细解释:diff[i] += 3 意味着给 nums[i..] 所有的元素都加了 3,然后 diff[j+1] -= 3 又意味着对于 nums[j+1..] 所有元素再减 3,那综合起来,是不是就是对 nums[i..j] 中的所有元素都加 3

差分数组模板

# 差分数组工具类
class Difference:
    # 差分数组
    def __init__(self, nums: List[int]):
        assert len(nums) > 0
        self.diff = [0] * len(nums)
        # 根据初始数组构造差分数组
        self.diff[0] = nums[0]
        for i in range(1, len(nums)):
            self.diff[i] = nums[i] - nums[i - 1]

    # 给闭区间 [i, j] 增加 val(可以是负数)
    def increment(self, i: int, j: int, val: int) -> None:
        self.diff[i] += val
        if j + 1 < len(self.diff):
            self.diff[j + 1] -= val

    # 返回结果数组
    def result(self) -> List[int]:
        res = [0] * len(self.diff)
        # 根据差分数组构造结果数组
        res[0] = self.diff[0]
        for i in range(1, len(self.diff)):
            res[i] = res[i - 1] + self.diff[i]
        return res

二维差分数组模板

#构建二维差分数组
g = [[0] * (n + 2) for _ in range(n + 2)]#初始化二维差分数组
for _ in range(m):
    x1, y1, x2, y2 = map(int, input().split())
    g[x1][y1] += 1
    g[x2 + 1][y1] -= 1
    g[x1][y2 + 1] -= 1
    g[x2 + 1][y2 + 1] += 1

#根据二维差分数组得到前缀和数组
for i in range(1, n + 1):
    for j in range(1, n + 1):
        g[i][j] += g[i - 1][j] + g[i][j - 1] - g[i - 1][j - 1]
posted @ 2024-03-27 13:17  Frommoon  阅读(18)  评论(0编辑  收藏  举报