构建前缀信息
class NumArray {
public int[] prefixSum;
public NumArray(int[] nums) {
prefixSum = new int[nums.length + 1];
// 计算前缀和
for (int i = 1; i <= nums.length; i++)
prefixSum[i] = prefixSum[i - 1] + nums[i - 1];
}
public int sumRange(int left, int right) {
return prefixSum[right + 1] - prefixSum[left];
}
}
- 构建前缀和最早出现的位置,返回无序数组中累加和为给定值的最长子数组的长度
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int len = in.nextInt();
int k = in.nextInt();
int[] nums = new int[len];
for (int i = 0; i < len; i++) {
nums[i] = in.nextInt();
}
int res = 0;
// 前缀和
int[] prefixSum = new int[len + 1];
// 记录前缀和第一次出现的位置
Map<Integer, Integer> hashMap = new HashMap<>();
// 初始就有一个前缀和为0
hashMap.put(0, 0);
for (int i = 1; i <= len; i++) {
prefixSum[i] = prefixSum[i - 1] + nums[i - 1];
// 更新长度
if (hashMap.containsKey(prefixSum[i] - k))
res = Math.max(res, i - hashMap.get(prefixSum[i] - k));
// 记录首次出现位置
if (!hashMap.containsKey(prefixSum[i])) hashMap.put(prefixSum[i], i);
}
System.out.println(res);
}
}
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int len = in.nextInt();
int k = in.nextInt();
int[] nums = new int[len];
for (int i = 0; i < len; i++) {
nums[i] = in.nextInt();
}
int res = 0;
// 前缀和,只与前一项有关,可以省去数组
int prefixSum = 0;
// 记录前缀和第一次出现的位置
Map<Integer, Integer> hashMap = new HashMap<>();
hashMap.put(0, 0);
for (int i = 1; i <= len; i++) {
prefixSum += nums[i - 1];
// 更新长度
if (hashMap.containsKey(prefixSum - k))
res = Math.max(res, i - hashMap.get(prefixSum - k));
// 记录首次出现位置
if (!hashMap.containsKey(prefixSum)) hashMap.put(prefixSum, i);
}
System.out.println(res);
}
}
- 构建前缀和出现的次数,返回无序数组中累加和为给定值的子数组的个数
import java.util.HashMap;
import java.util.Map;
public class Solution {
public int subarraySum(int[] nums, int k) {
int res = 0;
// 记录前缀和以及出现次数
Map<Integer, Integer> map = new HashMap<>();
// 前缀和为0的至少出现一次
map.put(0, 1);
int prefixSum = 0;
for (int i = 1; i <= nums.length; i++) {
prefixSum += nums[i - 1];
res += map.getOrDefault(prefixSum - k, 0);
// 累计出现次数
map.put(prefixSum, map.getOrDefault(prefixSum, 0) + 1);
}
return res;
}
public static void main(String[] args) {
int[] nums = {1, 1, 1};
System.out.println(new Solution().subarraySum(nums, 2));
}
}
- 构建前缀和最早出现的位置,返回无序数组中,正负数个数相等的最长子数组的长度
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int len = in.nextInt();
int[] nums = new int[len];
for (int i = 0; i < len; i++)
nums[i] = in.nextInt();
int res = 0;
// 记录前缀中正数和负数的差值(正数个数-负数个数)
int prefix = 0;
// 记录prefix和其位置
Map<Integer, Integer> map = new HashMap<>();
map.put(0, 0);
for (int i = 1; i <= len; i++) {
if (nums[i - 1] > 0)
prefix++;
else if (nums[i - 1] < 0)
prefix--;
if (map.containsKey(prefix))
// 找到该值上次出现的位置
res = Math.max(res, i - map.get(prefix));
else
// 记录prefix首次出现位置
map.put(prefix, i);
}
System.out.println(res);
}
}
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int len = in.nextInt();
int[] nums = new int[len];
for (int i = 0; i < len; i++) {
int temp = in.nextInt();
// 接受输入数据的时候就处理
nums[i] = temp != 0 ? (temp > 0 ? 1 : -1) : 0;
}
int res = 0;
// 记录前缀中正数和负数的差值(正数个数-负数个数)
int prefix = 0;
// 记录prefix和其位置
Map<Integer, Integer> map = new HashMap<>();
map.put(0, 0);
for (int i = 1; i <= len; i++) {
prefix += nums[i - 1];
if (map.containsKey(prefix))
// 找到该值上次出现的位置
res = Math.max(res, i - map.get(prefix));
else
// 记录prefix首次出现位置
map.put(prefix, i);
}
System.out.println(res);
}
}
- 构建前缀和最早出现的位置。表现良好的最长时间段问题
import java.util.HashMap;
import java.util.Map;
class Solution {
public int longestWPI(int[] hours) {
int res = 0;
// 记录前缀中大于8h的天数和小于等于8h的天数之差
int prefix = 0;
// 记录差值和下标
Map<Integer, Integer> map = new HashMap<>();
map.put(0, 0);
for (int i = 1; i <= hours.length; i++) {
prefix += hours[i - 1] > 8 ? 1 : -1;
if (prefix > 0) {
// 从数组开头到当前位置符合要求
res = i;
} else {
// 若当前prefix为-3,则找-4是否已经出现,若出现,则说明-4出现的位置到当前位置的子数组是符合条件的(大于8h的天数严格大于一半)
// 若之前还有-5、-6啥的,其之前一定出现过-4,因为是从0开始加一减一的,先出现-4才可能出现-5、-6
if (map.containsKey(prefix - 1))
res = Math.max(res, i - map.get(prefix - 1));
}
if (!map.containsKey(prefix)) map.put(prefix, i);
}
return res;
}
}
- 构建前缀和余数最早出现的位置。移除的最短子数组长度,使得剩余元素的累加和能被p整除
import java.util.HashMap;
import java.util.Map;
class Solution {
public int minSubarray(int[] nums, int p) {
// 总体和模p的余数,也是需要删除的部分的累加和模p的余数
int delete = 0;
for (int num : nums) delete = (delete + num) % p;
// 不需要移除子数组
if (delete == 0) return 0;
int res = 0x7fffffff;
// 记录累加和
int prefixSum = 0;
// key为模p的余数,value为该值最后一次出现的位置
Map<Integer, Integer> map = new HashMap<>();
map.put(0, 0);
for (int i = 1; i <= nums.length; i++) {
prefixSum = (prefixSum + nums[i - 1]) % p;
// 当前位置的前缀和模p的值为prefixSum,整体数组累加和模p的值为delete
// 需要删除子数组的累加和模p的值为delete,这样删除元素后的整体数组模p的值才能为0,才能被p整除
// 所以要往前寻找累加和模p的值为find最后一次出现的位置,才能使删除的数组长度最小
int find = (prefixSum - delete + p) % p;
if (map.containsKey(find))
res = Math.min(res, i - map.get(find));
// 记录prefixSum最后一次出现的位置
map.put(prefixSum, i);
}
// 没得删或者要全删时返回-1
return (res == 0x7fffffff || res == nums.length) ? -1 : res;
}
}
- 构建前缀奇偶状态最早出现的位置。每个元音包含偶数次的最长子串长度
import java.util.Arrays;
class Solution {
public int findTheLongestSubstring(String s) {
int len = s.length();
// 只有5个元音字符,状态5位,状态总数32种
int[] map = new int[32];
// -2表示这个状态之前没出现过
Arrays.fill(map, -2);
// aeiou 00000
map[0] = -1;
int ans = 0;
// status低5位从低到高分表表示aeiou的奇偶性,0为偶,1为奇
int status = 0;
// aeiou在status中对应的位置
int m;
for (int i = 0; i < len; i++) {
// 当前字符
m = move(s.charAt(i));
// 情况1 : 当前字符不是元音,status不变
// 情况2 : 当前字符是元音,a~u(0~4),修改相应的状态,亦或运算改变对应元音字符的奇偶性
if (m != -1) status ^= 1 << m;
if (map[status] != -2) {
// 同样的状态,之前最早出现在哪
ans = Math.max(ans, i - map[status]);
} else {
// 记录状态第一次出现的位置
map[status] = i;
}
}
return ans;
}
public static int move(char cha) {
switch (cha) {
case 'a':
return 0;
case 'e':
return 1;
case 'i':
return 2;
case 'o':
return 3;
case 'u':
return 4;
default:
return -1;
}
}
}