LeetCode高频算法解题套路-前缀和与差分数组
1. 原理简介
1.1 前缀和(Prefix Sum)
定义:prefix[i] = nums[0] + nums[1] + ... + nums[i-1]
**用途:**快速求某一区间 [l, r]
的和:prefix[r+1] - prefix[l]
1.2 差分数组(Difference Array)
定义:diff[i] = nums[i] - nums[i-1]
,逆运算为前缀和,对差分数组求前缀和,即可得到原数组。
**用途:**快速对区间 [l, r]
做加减操作,再还原原数组。当我们希望对原数组的某一个区间 [l,r] 施加一个增量inc 时,差分数组 d 对应的改变是:d[l] 增加 inc,d[r+1] 减少 inc。这样对于区间的修改就变为了对于两个位置的修改。并且这种修改是可以叠加的,即当我们多次对原数组的不同区间施加不同的增量,我们只要按规则修改差分数组即可。
2. 典型题目
2.1 前缀和
LeetCode - 303. 区域和检索 - 数组不可变
难度:简单
题目:给定一个整数数组
nums
,处理以下类型的多个查询:
- 计算索引
left
和right
(包含left
和right
)之间的nums
元素的 和 ,其中left <= right
实现
NumArray
类:
NumArray(int[] nums)
使用数组nums
初始化对象int sumRange(int i, int j)
返回数组nums
中索引left
和right
之间的元素的 总和 ,包含left
和right
两点(也就是nums[left] + nums[left + 1] + ... + nums[right]
)
解题思路:
很简单的题目,求指定区间的和,完全符合前缀和适用场景。
1 | class NumArray { |
复杂度分析:
时间复杂度:O(n), sumRange方法O(1)
空间复杂度:O(n)
LeetCode - 724. 寻找数组的中心下标
难度:简单
题目:给你一个整数数组
nums
,请计算数组的 中心下标 。数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。
如果中心下标位于数组最左端,那么左侧数之和视为
0
,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回
-1
。
解题思路:
- 第1次遍历,预计算前缀和,并对左右两侧分别扩充1个0
- 第2次遍历,找到下标
i
满足psa[i-1] == psa[len+1] - psa[i]
,否则返回 -1
1 | class Solution { |
复杂度分析:
时间复杂度:O(n)
空间复杂度:O(n)
LeetCode - 560. 和为 K 的子数组
《 LeetCode高频算法解题套路-哈希表》
2.2 差分数组
LeetCode - 1109. 航班预订统计
难度:中等
题目:这里有
n
个航班,它们分别从1
到n
进行编号。有一份航班预订表
bookings
,表中第i
条预订记录bookings[i] = [firsti, lasti, seatsi]
意味着在从firsti
到lasti
(包含firsti
和lasti
)的 每个航班 上预订了seatsi
个座位。请你返回一个长度为
n
的数组answer
,里面的元素是每个航班预定的座位总数。
解题思路:
- 将所有指定区间
[first, last]
的增量seats
累计到一个差分数组。(累计方法:diff[first] += seats; diff[last+1] -= seats;
,注:last+1需判定数组下标越界) - 对diff数组求前缀和
1 | class Solution { |
复杂度分析:
时间复杂度:O(n)
空间复杂度:O(n)
LeetCode - 1094. 拼车
难度:中等
题目:车上最初有
capacity
个空座位。车 只能 向一个方向行驶(也就是说,不允许掉头或改变方向)给定整数
capacity
和一个数组trips
,trip[i] = [numPassengersi, fromi, toi]
表示第i
次旅行有numPassengersi
乘客,接他们和放他们的位置分别是fromi
和toi
。这些位置是从汽车的初始位置向东的公里数。当且仅当你可以在所有给定的行程中接送所有乘客时,返回
true
,否则请返回false
。
解题思路:
和 1109.航班预订统计 一样
1 | class Solution { |
复杂度分析:
时间复杂度:O(n)
空间复杂度:O(n)