一、题目描述
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
示例 1:
输入: s = "cbaebabacd", p = "abc"
输出: [0,6]
解释:
起始索引等于 0 的子串是 "cba", 它是 "abc" 的异位词。
起始索引等于 6 的子串是 "bac", 它是 "abc" 的异位词。
示例 2:
输入: s = "abab", p = "ab"
输出: [0,1,2]
解释:
起始索引等于 0 的子串是 "ab", 它是 "ab" 的异位词。
起始索引等于 1 的子串是 "ba", 它是 "ab" 的异位词。
起始索引等于 2 的子串是 "ab", 它是 "ab" 的异位词。
提示:
1 <= s.length, p.length <= 3 * 104
s 和 p 仅包含小写字母
二、解决思路
1、直观解法,for循环遍历原数组,每次截取p长度,判断是否是异位词
class Solution {
public List<Integer> findAnagrams(String s, String p) {
List<Integer> list = new LinkedList<>();
if(s == null || p == null || s.length() == 0 || p.length() == 0){
return list;
}
if(p.length() > s.length()){
return list;
}
int count = p.length();
String cur;
char[] curChars;
Set<String> set = new HashSet<>();
//需转换为数组进行排序
set.add(sortString(p));
for(int i = 0;i < s.length() && i < s.length() - count + 1;i++){
//截取不包含i+count位置的元素
cur = s.substring(i,i + count);
if(set.contains(sortString(cur))){
list.add(i);
}
}
return list;
}
//对一个字符串内部按字母排序,返回新字符串
public String sortString(String str){
char[] dest = str.toCharArray();
Arrays.sort(dest);
return String.valueOf(dest);
}
}

2、滑动窗口
定长滑窗。枚举 s 的所有长为 n 的子串 s
′
,如果 s
′
的每种字母的出现次数,和 p 的每种字母的出现次数都相同,那么 s
′
是 p 的异位词。
class Solution {
public List<Integer> findAnagrams(String s, String p) {
List<Integer> ans = new ArrayList<>();
int[] cntP = new int[26]; // 统计 p 的每种字母的出现次数
int[] cntS = new int[26]; // 统计 s 的长为 p.length() 的子串 s' 的每种字母的出现次数
for (char c : p.toCharArray()) {
cntP[c - 'a']++; // 统计 p 的字母
}
for (int right = 0; right < s.length(); right++) {
cntS[s.charAt(right) - 'a']++; // 右端点字母进入窗口
int left = right - p.length() + 1;
if (left < 0) { // 窗口长度不足 p.length()
continue;
}
if (Arrays.equals(cntS, cntP)) { // s' 和 p 的每种字母的出现次数都相同
ans.add(left); // s' 左端点下标加入答案
}
cntS[s.charAt(left) - 'a']--; // 左端点字母离开窗口
}
return ans;
}
}
