packageclass041;// 求最大公约数、最小公倍数publicclassCode01_GcdAndLcm{// 证明辗转相除法就是证明如下关系:// gcd(a, b) = gcd(b, a % b)// 假设a % b = r,即需要证明的关系为:gcd(a, b) = gcd(b, r)// 证明过程:// 因为a % b = r,所以如下两个等式必然成立// 1) a = b * q + r,q为0、1、2、3....中的一个整数// 2) r = a − b * q,q为0、1、2、3....中的一个整数// 假设u是a和b的公因子,则有: a = s * u, b = t * u// 把a和b带入2)得到,r = s * u - t * u * q = (s - t * q) * u// 这说明 : u如果是a和b的公因子,那么u也是r的因子// 假设v是b和r的公因子,则有: b = x * v, r = y * v// 把b和r带入1)得到,a = x * v * q + y * v = (x * q + y) * v// 这说明 : v如果是b和r的公因子,那么v也是a的公因子// 综上,a和b的每一个公因子 也是 b和r的一个公因子,反之亦然// 所以,a和b的全体公因子集合 = b和r的全体公因子集合// 即gcd(a, b) = gcd(b, r)// 证明结束publicstaticlonggcd(long a,long b){return b ==0? a :gcd(b, a % b);}publicstaticlonglcm(long a,long b){return(long) a /gcd(a, b)* b;}}
packageclass041;// 一个正整数如果能被 a 或 b 整除,那么它是神奇的。// 给定三个整数 n , a , b ,返回第 n 个神奇的数字。// 因为答案可能很大,所以返回答案 对 10^9 + 7 取模 后的值。// 测试链接 : https://leetcode.cn/problems/nth-magical-number/publicclassCode02_NthMagicalNumber{publicstaticintnthMagicalNumber(int n,int a,int b){long lcm =lcm(a, b);long ans =0;// l = 0// r = (long) n * Math.min(a, b)// l......rfor(long l =0, r =(long) n *Math.min(a, b), m =0; l <= r;){
m =(l + r)/2;// 1....mif(m / a + m / b - m / lcm >= n){
ans = m;
r = m -1;}else{
l = m +1;}}return(int)(ans %1000000007);}publicstaticlonggcd(long a,long b){return b ==0? a :gcd(b, a % b);}publicstaticlonglcm(long a,long b){return(long) a /gcd(a, b)* b;}}
packageclass041;importjava.math.BigInteger;// 加法、减法、乘法的同余原理// 不包括除法,因为除法必须求逆元,后续课讲述publicclassCode03_SameMod{// 为了测试publicstaticlongrandom(){return(long)(Math.random()*Long.MAX_VALUE);}// 计算 ((a + b) * (c - d) + (a * c - b * d)) % mod 的非负结果publicstaticintf1(long a,long b,long c,long d,int mod){BigInteger o1 =newBigInteger(String.valueOf(a));// aBigInteger o2 =newBigInteger(String.valueOf(b));// bBigInteger o3 =newBigInteger(String.valueOf(c));// cBigInteger o4 =newBigInteger(String.valueOf(d));// dBigInteger o5 = o1.add(o2);// a + bBigInteger o6 = o3.subtract(o4);// c - dBigInteger o7 = o1.multiply(o3);// a * cBigInteger o8 = o2.multiply(o4);// b * dBigInteger o9 = o5.multiply(o6);// (a + b) * (c - d)BigInteger o10 = o7.subtract(o8);// (a * c - b * d)BigInteger o11 = o9.add(o10);// ((a + b) * (c - d) + (a * c - b * d))// ((a + b) * (c - d) + (a * c - b * d)) % modBigInteger o12 = o11.mod(newBigInteger(String.valueOf(mod)));if(o12.signum()==-1){// 如果是负数那么+mod返回return o12.add(newBigInteger(String.valueOf(mod))).intValue();}else{// 如果不是负数直接返回return o12.intValue();}}// 计算 ((a + b) * (c - d) + (a * c - b * d)) % mod 的非负结果publicstaticintf2(long a,long b,long c,long d,int mod){int o1 =(int)(a % mod);// aint o2 =(int)(b % mod);// bint o3 =(int)(c % mod);// cint o4 =(int)(d % mod);// dint o5 =(o1 + o2)% mod;// a + bint o6 =(o3 - o4 + mod)% mod;// c - dint o7 =(int)(((long) o1 * o3)% mod);// a * cint o8 =(int)(((long) o2 * o4)% mod);// b * dint o9 =(int)(((long) o5 * o6)% mod);// (a + b) * (c - d)int o10 =(o7 - o8 + mod)% mod;// (a * c - b * d)int ans =(o9 + o10)% mod;// ((a + b) * (c - d) + (a * c - b * d)) % modreturn ans;}publicstaticvoidmain(String[] args){System.out.println("测试开始");int testTime =100000;int mod =1000000007;for(int i =0; i < testTime; i++){long a =random();long b =random();long c =random();long d =random();if(f1(a, b, c, d, mod)!=f2(a, b, c, d, mod)){System.out.println("出错了!");}}System.out.println("测试结束");System.out.println("===");long a =random();long b =random();long c =random();long d =random();System.out.println("a : "+ a);System.out.println("b : "+ b);System.out.println("c : "+ c);System.out.println("d : "+ d);System.out.println("===");System.out.println("f1 : "+f1(a, b, c, d, mod));System.out.println("f2 : "+f2(a, b, c, d, mod));}}
42. (必备)对数器打表找规律的技巧
packageclass042;// 有装下8个苹果的袋子、装下6个苹果的袋子,一定要保证买苹果时所有使用的袋子都装满// 对于无法装满所有袋子的方案不予考虑,给定n个苹果,返回至少要多少个袋子// 如果不存在每个袋子都装满的方案返回-1publicclassCode01_AppleMinBags{publicstaticintbags1(int apple){int ans =f(apple);return ans ==Integer.MAX_VALUE?-1: ans;}// 当前还有rest个苹果,使用的每个袋子必须装满,返回至少几个袋子publicstaticintf(int rest){if(rest <0){returnInteger.MAX_VALUE;}if(rest ==0){return0;}// 使用8规格的袋子,剩余的苹果还需要几个袋子,有可能返回无效解int p1 =f(rest -8);// 使用6规格的袋子,剩余的苹果还需要几个袋子,有可能返回无效解int p2 =f(rest -6);
p1 += p1 !=Integer.MAX_VALUE?1:0;
p2 += p2 !=Integer.MAX_VALUE?1:0;returnMath.min(p1, p2);}publicstaticintbags2(int apple){if((apple &1)!=0){return-1;}if(apple <18){if(apple ==0){return0;}if(apple ==6|| apple ==8){return1;}if(apple ==12|| apple ==14|| apple ==16){return2;}return-1;}return(apple -18)/8+3;}publicstaticvoidmain(String[] args){for(int apple =0; apple <100; apple++){System.out.println(apple +" : "+bags1(apple));}}}
packageclass044;// 用固定数组实现前缀树,空间使用是静态的。推荐!// 测试链接 : https://www.nowcoder.com/practice/7f8a8553ddbf4eaab749ec988726702b// 请同学们务必参考如下代码中关于输入、输出的处理// 这是输入输出处理效率很高的写法// 提交以下的code,提交时请把类名改成"Main",可以直接通过importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.OutputStreamWriter;importjava.io.PrintWriter;importjava.util.Arrays;publicclassCode02_TrieTree{// 如果将来增加了数据量,就改大这个值publicstaticintMAXN=150001;publicstaticint[][] tree =newint[MAXN][26];publicstaticint[] end =newint[MAXN];publicstaticint[] pass =newint[MAXN];publicstaticint cnt;publicstaticvoidbuild(){
cnt =1;}publicstaticvoidinsert(String word){int cur =1;
pass[cur]++;for(int i =0, path; i < word.length(); i++){
path = word.charAt(i)-'a';if(tree[cur][path]==0){
tree[cur][path]=++cnt;}
cur = tree[cur][path];
pass[cur]++;}
end[cur]++;}publicstaticintsearch(String word){int cur =1;for(int i =0, path; i < word.length(); i++){
path = word.charAt(i)-'a';if(tree[cur][path]==0){return0;}
cur = tree[cur][path];}return end[cur];}publicstaticintprefixNumber(String pre){int cur =1;for(int i =0, path; i < pre.length(); i++){
path = pre.charAt(i)-'a';if(tree[cur][path]==0){return0;}
cur = tree[cur][path];}return pass[cur];}publicstaticvoiddelete(String word){if(search(word)>0){int cur =1;for(int i =0, path; i < word.length(); i++){
path = word.charAt(i)-'a';if(--pass[tree[cur][path]]==0){
tree[cur][path]=0;return;}
cur = tree[cur][path];}
end[cur]--;}}publicstaticvoidclear(){for(int i =1; i <= cnt; i++){Arrays.fill(tree[i],0);
end[i]=0;
pass[i]=0;}}publicstaticint m, op;publicstaticString[] splits;publicstaticvoidmain(String[] args)throwsIOException{BufferedReader in =newBufferedReader(newInputStreamReader(System.in));PrintWriter out =newPrintWriter(newOutputStreamWriter(System.out));String line =null;while((line = in.readLine())!=null){build();
m =Integer.valueOf(line);for(int i =1; i <= m; i++){
splits = in.readLine().split(" ");
op =Integer.valueOf(splits[0]);if(op ==1){insert(splits[1]);}elseif(op ==2){delete(splits[1]);}elseif(op ==3){
out.println(search(splits[1])>0?"YES":"NO");}elseif(op ==4){
out.println(prefixNumber(splits[1]));}}clear();}
out.flush();
in.close();
out.close();}}
45. (必备)前缀树的相关题目
packageclass045;importjava.util.Arrays;// 牛牛和他的朋友们约定了一套接头密匙系统,用于确认彼此身份// 密匙由一组数字序列表示,两个密匙被认为是一致的,如果满足以下条件:// 密匙 b 的长度不超过密匙 a 的长度。// 对于任意 0 <= i < length(b),有b[i+1] - b[i] == a[i+1] - a[i]// 现在给定了m个密匙 b 的数组,以及n个密匙 a 的数组// 请你返回一个长度为 m 的结果数组 ans,表示每个密匙b都有多少一致的密匙// 数组 a 和数组 b 中的元素个数均不超过 10^5// 1 <= m, n <= 1000// 测试链接 : https://www.nowcoder.com/practice/c552d3b4dfda49ccb883a6371d9a6932publicclassCode01_CountConsistentKeys{publicstaticint[]countConsistentKeys(int[][] b,int[][] a){build();StringBuilder builder =newStringBuilder();// [3,6,50,10] -> "3#44#-40#"for(int[] nums : a){
builder.setLength(0);for(int i =1; i < nums.length; i++){
builder.append(String.valueOf(nums[i]- nums[i -1])+"#");}insert(builder.toString());}int[] ans =newint[b.length];for(int i =0; i < b.length; i++){
builder.setLength(0);int[] nums = b[i];for(int j =1; j < nums.length; j++){
builder.append(String.valueOf(nums[j]- nums[j -1])+"#");}
ans[i]=count(builder.toString());}clear();return ans;}// 如果将来增加了数据量,就改大这个值publicstaticintMAXN=2000001;publicstaticint[][] tree =newint[MAXN][12];publicstaticint[] pass =newint[MAXN];publicstaticint cnt;publicstaticvoidbuild(){
cnt =1;}// '0' ~ '9' 10个 0~9// '#' 10// '-' 11publicstaticintpath(char cha){if(cha =='#'){return10;}elseif(cha =='-'){return11;}else{return cha -'0';}}publicstaticvoidinsert(String word){int cur =1;
pass[cur]++;for(int i =0, path; i < word.length(); i++){
path =path(word.charAt(i));if(tree[cur][path]==0){
tree[cur][path]=++cnt;}
cur = tree[cur][path];
pass[cur]++;}}publicstaticintcount(String pre){int cur =1;for(int i =0, path; i < pre.length(); i++){
path =path(pre.charAt(i));if(tree[cur][path]==0){return0;}
cur = tree[cur][path];}return pass[cur];}publicstaticvoidclear(){for(int i =1; i <= cnt; i++){Arrays.fill(tree[i],0);
pass[i]=0;}}}
packageclass045;importjava.util.HashSet;// 数组中两个数的最大异或值// 给你一个整数数组 nums ,返回 nums[i] XOR nums[j] 的最大运算结果,其中 0<=i<=j<=n// 1 <= nums.length <= 2 * 10^5// 0 <= nums[i] <= 2^31 - 1// 测试链接 : https://leetcode.cn/problems/maximum-xor-of-two-numbers-in-an-array/publicclassCode02_TwoNumbersMaximumXor{// 前缀树的做法// 好想publicstaticintfindMaximumXOR1(int[] nums){build(nums);int ans =0;for(int num : nums){
ans =Math.max(ans,maxXor(num));}clear();return ans;}// 准备这么多静态空间就够了,实验出来的// 如果测试数据升级了规模,就改大这个值publicstaticintMAXN=3000001;publicstaticint[][] tree =newint[MAXN][2];// 前缀树目前使用了多少空间publicstaticint cnt;// 数字只需要从哪一位开始考虑publicstaticint high;publicstaticvoidbuild(int[] nums){
cnt =1;// 找个最大值int max =Integer.MIN_VALUE;for(int num : nums){
max =Math.max(num, max);}// 计算数组最大值的二进制状态,有多少个前缀的0// 可以忽略这些前置的0,从left位开始考虑
high =31-Integer.numberOfLeadingZeros(max);for(int num : nums){insert(num);}}publicstaticvoidinsert(int num){int cur =1;for(int i = high, path; i >=0; i--){
path =(num >> i)&1;if(tree[cur][path]==0){
tree[cur][path]=++cnt;}
cur = tree[cur][path];}}publicstaticintmaxXor(int num){// 最终异或的结果(尽量大)int ans =0;// 前缀树目前来到的节点编号int cur =1;for(int i = high, status, want; i >=0; i--){// status : num第i位的状态
status =(num >> i)&1;// want : num第i位希望遇到的状态
want = status ^1;if(tree[cur][want]==0){// 询问前缀树,能不能达成// 不能达成
want ^=1;}// want变成真的往下走的路
ans |=(status ^ want)<< i;
cur = tree[cur][want];}return ans;}publicstaticvoidclear(){for(int i =1; i <= cnt; i++){
tree[i][0]= tree[i][1]=0;}}// 用哈希表的做法// 难想publicintfindMaximumXOR2(int[] nums){int max =Integer.MIN_VALUE;for(int num : nums){
max =Math.max(num, max);}int ans =0;HashSet<Integer> set =newHashSet<>();for(int i =31-Integer.numberOfLeadingZeros(max); i >=0; i--){// ans : 31....i+1 已经达成的目标int better = ans |(1<< i);
set.clear();for(int num : nums){// num : 31.....i 这些状态保留,剩下全成0
num =(num >> i)<< i;
set.add(num);// num ^ 某状态 是否能 达成better目标,就在set中找 某状态 : better ^ numif(set.contains(better ^ num)){
ans = better;break;}}}return ans;}}
packageclass045;importjava.util.ArrayList;importjava.util.Arrays;importjava.util.List;// 在二维字符数组中搜索可能的单词// 给定一个 m x n 二维字符网格 board 和一个单词(字符串)列表 words// 返回所有二维网格上的单词。单词必须按照字母顺序,通过 相邻的单元格 内的字母构成// 其中“相邻”单元格是那些水平相邻或垂直相邻的单元格// 同一个单元格内的字母在一个单词中不允许被重复使用// 1 <= m, n <= 12// 1 <= words.length <= 3 * 10^4// 1 <= words[i].length <= 10// 测试链接 : https://leetcode.cn/problems/word-search-ii/publicclassCode03_WordSearchII{publicstaticList<String>findWords(char[][] board,String[] words){build(words);List<String> ans =newArrayList<>();for(int i =0; i < board.length; i++){for(int j =0; j < board[0].length; j++){dfs(board, i, j,1, ans);}}clear();return ans;}// board : 二维网格// i,j : 此时来到的格子位置,i行、j列// t : 前缀树的编号// List<String> ans : 收集到了哪些字符串,都放入ans// 返回值 : 收集到了几个字符串publicstaticintdfs(char[][] board,int i,int j,int t,List<String> ans){// 越界 或者 走了回头路,直接返回0if(i <0|| i == board.length || j <0|| j == board[0].length || board[i][j]==0){return0;}// 不越界 且 不是回头路// 用tmp记录当前字符char tmp = board[i][j];// 路的编号// a -> 0// b -> 1// ...// z -> 25int road = tmp -'a';
t = tree[t][road];if(pass[t]==0){return0;}// i,j位置有必要来// fix :从当前i,j位置出发,一共收集到了几个字符串int fix =0;if(end[t]!=null){
fix++;
ans.add(end[t]);
end[t]=null;}// 把i,j位置的字符,改成0,后续的过程,是不可以再来到i,j位置的!
board[i][j]=0;
fix +=dfs(board, i -1, j, t, ans);
fix +=dfs(board, i +1, j, t, ans);
fix +=dfs(board, i, j -1, t, ans);
fix +=dfs(board, i, j +1, t, ans);
pass[t]-= fix;
board[i][j]= tmp;return fix;}publicstaticintMAXN=10001;publicstaticint[][] tree =newint[MAXN][26];publicstaticint[] pass =newint[MAXN];publicstaticString[] end =newString[MAXN];publicstaticint cnt;publicstaticvoidbuild(String[] words){
cnt =1;for(String word : words){int cur =1;
pass[cur]++;for(int i =0, path; i < word.length(); i++){
path = word.charAt(i)-'a';if(tree[cur][path]==0){
tree[cur][path]=++cnt;}
cur = tree[cur][path];
pass[cur]++;}
end[cur]= word;}}publicstaticvoidclear(){for(int i =1; i <= cnt; i++){Arrays.fill(tree[i],0);
pass[i]=0;
end[i]=null;}}}
46. (必备)构建前缀数量信息的技巧-解决子数组相关问题
packageclass046;// 利用前缀和快速得到区域累加和// 测试链接 : https://leetcode.cn/problems/range-sum-query-immutable/publicclassCode01_PrefixSumArray{classNumArray{publicint[] sum;publicNumArray(int[] nums){
sum =newint[nums.length +1];for(int i =1; i <= nums.length; i++){
sum[i]= sum[i -1]+ nums[i -1];}}publicintsumRange(int left,int right){return sum[right +1]- sum[left];}}}
packageclass046;// 返回无序数组中累加和为给定值的最长子数组长度// 给定一个无序数组arr, 其中元素可正、可负、可0// 给定一个整数aim// 求arr所有子数组中累加和为aim的最长子数组长度// 测试链接 : https://www.nowcoder.com/practice/36fb0fd3c656480c92b569258a1223d5// 请同学们务必参考如下代码中关于输入、输出的处理// 这是输入输出处理效率很高的写法// 提交以下的code,提交时请把类名改成"Main",可以直接通过importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.OutputStreamWriter;importjava.io.PrintWriter;importjava.io.StreamTokenizer;importjava.util.HashMap;publicclassCode02_LongestSubarraySumEqualsAim{publicstaticintMAXN=100001;publicstaticint[] arr =newint[MAXN];publicstaticint n, aim;// key : 某个前缀和// value : 这个前缀和最早出现的位置publicstaticHashMap<Integer,Integer> map =newHashMap<>();publicstaticvoidmain(String[] args)throwsIOException{BufferedReader br =newBufferedReader(newInputStreamReader(System.in));StreamTokenizer in =newStreamTokenizer(br);PrintWriter out =newPrintWriter(newOutputStreamWriter(System.out));while(in.nextToken()!=StreamTokenizer.TT_EOF){
n =(int) in.nval;
in.nextToken();
aim =(int) in.nval;for(int i =0; i < n; i++){
in.nextToken();
arr[i]=(int) in.nval;}
out.println(compute());}
out.flush();
out.close();
br.close();}publicstaticintcompute(){
map.clear();// 重要 : 0这个前缀和,一个数字也没有的时候,就存在了
map.put(0,-1);int ans =0;for(int i =0, sum =0; i < n; i++){
sum += arr[i];if(map.containsKey(sum - aim)){
ans =Math.max(ans, i - map.get(sum - aim));}if(!map.containsKey(sum)){
map.put(sum, i);}}return ans;}}
packageclass046;importjava.util.HashMap;// 返回无序数组中累加和为给定值的子数组个数// 测试链接 : https://leetcode.cn/problems/subarray-sum-equals-k/publicclassCode03_NumberOfSubarraySumEqualsAim{publicstaticintsubarraySum(int[] nums,int aim){HashMap<Integer,Integer> map =newHashMap<>();// 0这个前缀和,在没有任何数字的时候,已经有1次了
map.put(0,1);int ans =0;for(int i =0, sum =0; i < nums.length; i++){// sum : 0...i前缀和
sum += nums[i];
ans += map.getOrDefault(sum - aim,0);
map.put(sum, map.getOrDefault(sum,0)+1);}return ans;}}
packageclass046;importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.io.OutputStreamWriter;importjava.io.PrintWriter;importjava.io.StreamTokenizer;importjava.util.HashMap;// 返回无序数组中正数和负数个数相等的最长子数组长度// 给定一个无序数组arr,其中元素可正、可负、可0// 求arr所有子数组中正数与负数个数相等的最长子数组的长度// 测试链接 : https://www.nowcoder.com/practice/545544c060804eceaed0bb84fcd992fb// 请同学们务必参考如下代码中关于输入、输出的处理// 这是输入输出处理效率很高的写法// 提交以下的code,提交时请把类名改成"Main",可以直接通过publicclassCode04_PositivesEqualsNegtivesLongestSubarray{publicstaticintMAXN=100001;publicstaticint[] arr =newint[MAXN];publicstaticint n;publicstaticHashMap<Integer,Integer> map =newHashMap<>();publicstaticvoidmain(String[] args)throwsIOException{BufferedReader br =newBufferedReader(newInputStreamReader(System.in));StreamTokenizer in =newStreamTokenizer(br);PrintWriter out =newPrintWriter(newOutputStreamWriter(System.out));while(in.nextToken()!=StreamTokenizer.TT_EOF){
n =(int) in.nval;for(int i =0, num; i < n; i++){
in.nextToken();
num =(int) in.nval;
arr[i]= num !=0?(num >0?1:-1):0;}
out.println(compute());}
out.flush();
out.close();
br.close();}publicstaticintcompute(){
map.clear();
map.put(0,-1);int ans =0;for(int i =0, sum =0; i < n; i++){
sum += arr[i];if(map.containsKey(sum)){
ans =Math.max(ans, i - map.get(sum));}else{
map.put(sum, i);}}return ans;}}
packageclass046;importjava.util.HashMap;// 表现良好的最长时间段// 给你一份工作时间表 hours,上面记录着某一位员工每天的工作小时数// 我们认为当员工一天中的工作小时数大于 8 小时的时候,那么这一天就是 劳累的一天// 所谓 表现良好的时间段 ,意味在这段时间内,「劳累的天数」是严格 大于 不劳累的天数// 请你返回 表现良好时间段 的最大长度// 测试链接 : https://leetcode.cn/problems/longest-well-performing-interval/publicclassCode05_LongestWellPerformingInterval{publicstaticintlongestWPI(int[] hours){// 某个前缀和,最早出现的位置HashMap<Integer,Integer> map =newHashMap<>();// 0这个前缀和,最早出现在-1,一个数也没有的时候
map.put(0,-1);int ans =0;for(int i =0, sum =0; i < hours.length; i++){
sum += hours[i]>8?1:-1;if(sum >0){
ans = i +1;}else{// sum <= 0if(map.containsKey(sum -1)){
ans =Math.max(ans, i - map.get(sum -1));}}if(!map.containsKey(sum)){
map.put(sum, i);}}return ans;}}
packageclass046;importjava.util.HashMap;// 使数组和能被P整除// 给你一个正整数数组 nums,请你移除 最短 子数组(可以为 空)// 使得剩余元素的 和 能被 p 整除。 不允许 将整个数组都移除。// 请你返回你需要移除的最短子数组的长度,如果无法满足题目要求,返回 -1 。// 子数组 定义为原数组中连续的一组元素。// 测试链接 : https://leetcode.cn/problems/make-sum-divisible-by-p/publicclassCode06_MakeSumDivisibleByP{publicstaticintminSubarray(int[] nums,int p){// 整体余数int mod =0;for(int num : nums){
mod =(mod + num)% p;}if(mod ==0){return0;}// key : 前缀和%p的余数// value : 最晚出现的位置HashMap<Integer,Integer> map =newHashMap<>();
map.put(0,-1);int ans =Integer.MAX_VALUE;for(int i =0, cur =0, find; i < nums.length; i++){// 0...i这部分的余数
cur =(cur + nums[i])% p;
find = cur >= mod ?(cur - mod):(cur + p - mod);// find = (cur + p - mod) % p;if(map.containsKey(find)){
ans =Math.min(ans, i - map.get(find));}
map.put(cur, i);}return ans == nums.length ?-1: ans;}}
packageclass046;importjava.util.Arrays;// 每个元音包含偶数次的最长子字符串// 给你一个字符串 s ,请你返回满足以下条件的最长子字符串的长度// 每个元音字母,即 'a','e','i','o','u'// 在子字符串中都恰好出现了偶数次。// 测试链接 : https://leetcode.cn/problems/find-the-longest-substring-containing-vowels-in-even-counts/publicclassCode07_EvenCountsLongestSubarray{publicstaticintfindTheLongestSubstring(String s){int n = s.length();// 只有5个元音字符,状态就5位int[] map =newint[32];// map[0...31] = -2// map[01100] = -2, 这个状态之前没出现过Arrays.fill(map,-2);
map[0]=-1;int ans =0;for(int i =0, status =0, m; i < n; i++){// status : 0....i-1字符串上,aeiou的奇偶性// s[i] = 当前字符// 情况1 : 当前字符不是元音,status不变// 情况2 : 当前字符是元音,a~u(0~4),修改相应的状态
m =move(s.charAt(i));if(m !=-1){
status ^=1<< m;}// status: 0....i字符串上,aeiou的奇偶性// 同样的状态,之前最早出现在哪if(map[status]!=-2){
ans =Math.max(ans, i - map[status]);}else{
map[status]= i;}}return ans;}publicstaticintmove(char cha){switch(cha){case'a':return0;case'e':return1;case'i':return2;case'o':return3;case'u':return4;default:return-1;}}}