前缀和与差分数组
前缀和应用场景:原始数组不会被修改的情况下,频繁查询某个区间的累加和。
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]