import java.util.ArrayList; import java.util.List; public class FindAnagrams { //方法一:枚举所有长度为p.length()的子串 public List<Integer> findAnagrams1(String s, String p) { //定义一个结果列表 ArrayList<Integer> result = new ArrayList<>(); //1.统计p中字母出现的频次 int[] pCharCounts= new int[26]; for (int i = 0; i <p.length() ; i++) { pCharCounts[p.charAt(i)-'a']++; } //2.遍历s,以每一个字符作为起始,考察长度为p.length()的子串 for (int i = 0; i <=s.length()-p.length(); i++) { //3.判断当前子串是否为p的字母异位词 boolean isMatched = true; //定义一个数组,统计子串中所有字符频数 int[] sCharCounts= new int[26]; for (int j = i; j <i+p.length(); j++) { sCharCounts[s.charAt(j)-'a']++; //判断字符频次如果超过了p中的频次,就一定不符合 if(sCharCounts[s.charAt(j)-'a']>pCharCounts[s.charAt(j)-'a']){ isMatched = false; break; } } if(isMatched){ result.add(i); } } return result; } //方法二:滑动窗口,分别移动起始和结束位置 public List<Integer> findAnagrams(String s, String p) { //定义一个结果列表 ArrayList<Integer> result = new ArrayList<>(); //1.统计p中字母出现的频次 int[] pCharCounts= new int[26]; for (int i = 0; i <p.length() ; i++) { pCharCounts[p.charAt(i)-'a']++; } //定义一个数组,统计子串中所有字符频数 int[] subStringCharCounts= new int[26]; //定义双指针,指向窗口的起始和结束位置 int start = 0,end = 1; //2.移动指针,总是截取字符出现频次全部小于等于p中字符频次的子串 while (end<=s.length()){ //当前新增字符 char newChar = s.charAt(end-1); subStringCharCounts[newChar-'a']++; //3.判断当前子串是否符合要求 //如果新增字符导致子串频次超出p中频次,那么移动start,消除新增字符的影响 while (subStringCharCounts[newChar-'a']>pCharCounts[newChar-'a']&&start<end){ char removeChar = s.charAt(start); subStringCharCounts[removeChar-'a']--; start++; } //如果当前子串的长度等于p的长度,那么就算一个字母异位词 if(end-start==p.length()){ result.add(start); } end++; } return result; } public static void main(String[] args) { String s= "abab",p= "ab"; FindAnagrams findAnagrams = new FindAnagrams(); List<Integer> anagrams = findAnagrams.findAnagrams(s, p); System.out.println(anagrams); } }