这是我参与11月更文挑战的第27天,活动详情查看:2021最后一次更文挑战
差分数组
对应leetcode中的T370,T1109,T1094。
什么时候使用差分数组
当需要频繁的对原始数组对某个区间中的元素进行增减。比如一个数组nums,频繁的给nums[2...6] + 1,再-2 等等操作。
框架思维
差分数组类似于前缀和数组,如果要实现对区间[i, j]内的值加m
- 构造一个差分数组 - diff[i] = nums[i+1] - nums[i]
- 对差分数组中i的值加m - diff[i] += m
- 对差分数组中j+1的值减m - diff[j+1] -= m
原理
由于diff中存放的所有值都是后一个值与当前值相减得到的。那么diff[i]加了m,如果倒推回原数组,原数组中从i开始后的每个值都会加m,此时再对diff[j+1]减m,倒推回原数组时,j后的每个值也都减m了,就实现了对区间[i, j]加m的操作。
如图对diff[i]和diff[j + 1]分别做了加m和减m的操作
此时从diff倒推回nums - res[i] = nums[i - 1] + diff[i].
最终就可以实现对某区间数组值频繁增减的操作了。
实现代码
构造差分数组
diff[0] = nums[0]
for i in range(1, len(nums)):
diff[i] = nums[i] - nums[i - 1]
对差分数组进行增减操作
diff[i] += m
diff[j+1] -= m
从差分数组反推原数组
results = [ 0 for _ in range(len(diff))]
results[0] = diff[0]
for i in range(1, len(diff)):
results[i] = results[i - 1] + diff[i]
例题
以T1109为例 - 飞机航班从i站到j站总共的旅客数 - 求所有航班每站的总人数。
[i, j, k] 其实代表的是 第 i 站上来了 k 个人, 一直到 第 j 站都在飞机上,到第 j + 1 就不在飞机上了。所以第 i 站到第 j 站的每一站都会因此多 k 个人。
class Solution:
def corpFlightBookings(self, bookings: List[List[int]], n: int) -> List[int]:
# 初始化差分数组
diff = [0] * n
for first, last, seats in bookings:
# first - 1 是因为航班编号跟数组下标相差 1
# 对 first - 1 累加坐席数量
diff[first-1] += seats
# 最后一个不用处理
if last < n:
# last + 1 的位置减去 坐席数量
# 因为航班编号跟数组下标相差 1,因此直接用last
diff[last] -= seats
return list(accumulate(diff))