1. 前缀和
1.1 和为 K 的子数组
- 方法一:暴力枚举
public int subarraySum(int[] nums, int k) {
// 暴力枚举
int cnt = 0;
int n = nums.length;
for(int end=0;end<n;end++){
int sum = 0;
for(int start=end;start>=0;start--){
sum += nums[start];
if(sum == k) cnt++;
}
}
return cnt;
}
- 方法二:前缀和+哈希表
key:前缀和
value:该前缀和出现的次数
// k = pre[i]-pre[j-1]
// pre[j-1] = pre[i] - k
public int subarraySum(int[] nums, int k) {
int n = nums.length;
HashMap<Integer, Integer> map = new HashMap<>();
map.put(0, 1);
int cnt = 0;
int pre = 0;
// 计算前缀和数组
for(int i=0;i<n;i++){
pre += nums[i];
// 当前的前缀和已知,判断是否含有pre-k的前缀和,那么我们就知道某一区间的和为k了
if(map.containsKey(pre - k)) cnt += map.get(pre - k);
// 更新
map.put(pre, map.getOrDefault(pre,0) + 1);
}
return cnt;
}
1.2 连续数组
public int findMaxLength(int[] nums) {
// 把0看成-1,题目转换为:求前缀和为0的一段最长数组
// 0 = pre[i] - pre[j-1]
// 当pre[i] == pre[j-1]时满足条件
// 要求i-j+1的最大值
// key代表前缀和,value代表位置
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
int n = nums.length;
map.put(0, 0);
int pre = 0;
int maxn = 0;
for(int i=0;i<n;i++){
if(nums[i] == 0) pre--;
else pre++;
if(map.containsKey(pre)){
int j = map.get(pre); // 这个前缀和出现的下标最小的位置
if(i-j+1 > maxn) maxn = i-j+1;
}else{
map.put(pre, i+1); // 如果这个前缀和数值没出现过,则记录
}
}
return maxn;
}
1.3 连续的子数组和
public boolean checkSubarraySum(int[] nums, int k) {
// pre[i] - pre[j-1] = k*n
// pre[i]/k - pre[j-1]/k = n
// 要保证为整数,则pre[i]和pre[j-1]对k取余的结果要相同
int n = nums.length;
// key放per[i]%k的值, value放下标
HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
map.put(0, 0); // 一定要垫
int pre = 0;
for(int i=0;i<n;i++){
pre += nums[i];
int temp = pre%k;
if(map.containsKey(temp)){
int end = i+1; // 当前位置
int start = map.get(temp); // 出现相同余数位置的下标
if(end-start >= 2) return true;
}
else map.put(temp, i+1);
}
return false;
}
2. 差分
2.1 航班预订统计
public int[] corpFlightBookings(int[][] bookings, int n) {
int[] diff = new int[n+2];
int[] ans = new int[n];
int r = bookings.length; // 行数
for(int i=0;i<r;i++){
diff[bookings[i][0]] += bookings[i][2];
diff[bookings[i][1]+1] -= bookings[i][2];
}
ans[0] = diff[1] + diff[0];
for(int i=1;i<n;i++){
ans[i] = ans[i-1] + diff[i+1];
}
return ans;
}