文章目录
- 1094. 拼车
- 1109. 航班预定统计
- 303. 区域和检索 - 数组不可变
- 560. 和为K的子数组
- 523. 连续的子数组的和
1094. 拼车
class Solution {
public boolean carPooling(int[][] trips, int capacity) {
int[] diff = new int[1001]; // 记录每个站点改变的人数,比如增加几个人,减少几个人
for(int[] trip : trips){
int cnt = trip[0];
int from = trip[1];
int to = trip[2];
diff[from] += cnt;
diff[to] -= cnt;
}
int num = 0; // 记录每个站点车上的人数
for(int i = 0; i < 1001; i++){
num += diff[i];
if(num > capacity){
return false;
}
}
return true;
}
}
1109. 航班预定统计
原数组后一位元素 - 前一位元素,得到的就是差分数组
通过差分数组求前缀和,可以得到原数组。对原数组区间[l, r]增加inc,相当于对差分数组的diff[l] += inc,diff[r + 1] -= inc
class Solution {
public int[] corpFlightBookings(int[][] bookings, int n) {
int[] diff = new int[n];
int m = bookings.length;
for(int i = 0; i < m; i++){
int l = bookings[i][0];
int r = bookings[i][1];
int cnt = bookings[i][2];
diff[l - 1] += cnt;
if(r < n) diff[r] -= cnt;
}
for(int i = 1; i < n; i++){
diff[i] += diff[i - 1];
}
return diff;
}
}
303. 区域和检索 - 数组不可变
我们对原数组的[l, r]区间求和,可以转换为前缀和数组的差:pre[r] - pre[l - 1]
对前缀和求差分数组,可以得到原数组
对差分数组求前缀和,也可以得到原数组
class NumArray {
int n;
int[] pre;
public NumArray(int[] nums) {
n = nums.length;
pre = new int[n];
pre[0] = nums[0];
for(int i = 1; i < n; i++){
pre[i] = pre[i - 1] + nums[i];
}
}
public int sumRange(int l, int r) {
if(l == 0) return pre[r];
return pre[r] - pre[l - 1];
}
}
560. 和为K的子数组
class Solution {
public int subarraySum(int[] nums, int k) {
// 也就是前缀和数组两数之差为k
int n = nums.length;
int[] pre = new int[n];
pre[0] = nums[0];
for(int i = 1; i < n; i++){
pre[i] = pre[i - 1] + nums[i];
}
int ans = 0;
// presum, cnt
HashMap<Integer, Integer> map = new HashMap<>();
map.put(0, 1); // 表示pre[i]就是k,即[0,i]和为k
for(int i = 0; i < n; i++){
if(map.containsKey(pre[i] - k)){
ans += map.get(pre[i] - k);
}
map.put(pre[i], map.getOrDefault(pre[i], 0) + 1);
}
return ans;
}
}
523. 连续的子数组的和
若区间和为k的整数倍,说明前缀和数组两个元素的差应该是k的整数倍,也即每个元素%k后,余数相同。余数相同,则表示两数之差是k的整数倍
class Solution {
public boolean checkSubarraySum(int[] nums, int k) {
int n = nums.length;
int[] pre = new int[n];
pre[0] = nums[0];
for(int i = 1; i < n; i++){
pre[i] = pre[i - 1] + nums[i];
}
HashMap<Integer, Integer> map = new HashMap<>();
map.put(0, -2); // 如果前缀和数组 某个数 % k 的余数就是0,说明[0, i]区间的和就是k的整数倍,下标设置为-2
for(int i = 0; i < n; i++){
if(map.containsKey(pre[i] % k)){
if(i > 0 && i - map.get(pre[i] % k) >= 2){
// 同余的同时,还需要满足i > 0,因为i == 0时数组长度是1
return true;
}
}else{
// 余数已经出现过了,就不再更新了
map.put(pre[i] % k, i);
}
}
return false;
}
}
总结:
差分数组主要是把对原数组某个区间的操作,转换为对两端点的操作,[l, r] -> l, r + 1
前缀和数组可以把对原数组[l, r]区间求和的操作,转化为两端点的差pre[r] - pre[l - 1]