问题描述:给定一个字符串 s 和一个非空字符串 p,找到 s 中所有是 p 的字母异位词的子串,返回这些子串的起始索引。字符串只包含小写英文字母,并且字符串 s 和 p 的长度都不超过 20100。
说明:字母异位词指字母相同,但排列不同的字符串。不考虑答案输出的顺序。
示例 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" 的字母异位词。
//思路一:固定该滑动窗口大小,逐步平移该窗口
class Solution {
public List<Integer> findAnagrams(String s, String p) {
List<Integer> res = new ArrayList<>();
int l = 0;
int r = p.length();
//[l,r) 范围内字符,组成字符串
while (r<=s.length()){
String newP = s.substring(l,r);
if(isAnagram(newP,p)){
res.add(l);
}
l++;
r++;
}
return res;
}
//判断两个字符串是否是Anagram
//先判断长度是否相同,不相同,直接返回false
//统计 s1字符串中每个小写字母出现的频率,根据s2是否出现相同的字母以及出现的字母的频率是否相同
private boolean isAnagram(String word1,String word2){
if(word1.length() != word2.length()){
return false;
}
int[] freq = new int[26];
for(int i=0;i<word1.length();i++){
freq[word1.charAt(i)-'a']++;
}
for(int i=0;i<word2.length();i++){
char c = word2.charAt(i);
if(freq[c-'a']==0){
// word1 不包括字符 c,但是 word2 包括,则 word1 和 word2 必然不是字母异位词
return false;
}
freq[c-'a']--;
}
return true;
}
}
class Solution {
public List<Integer> findAnagrams(String s, String p) {
List<Integer> ret = new ArrayList<>();
if (s == null || s == "") {
return ret;
}
//统计字符串p中出现的小写字符的频率
int[] pFreq=new int[256];
//count是p中的字符数
int count=p.length();
for(int i=0;i<count;i++){
pFreq[p.charAt(i)]++;
}
int l=0,r=0;
//[l,r)表示滑动窗口
while(r<s.length()){
if(pFreq[s.charAt(r++)]-->=1){
//每次有一个p中字符进入窗口,扩展窗口,并且count–1
count--;
}
if(count==0){
//当count == 0的时候,表明我们的窗口中包含了p中的全部字符,得到一个结果。
ret.add(l);
}
if (r-l == p.length()) {
//当窗口包含一个结果以后,为了进一步遍历,我们需要缩小窗口使窗口不再包含全部的p,
//同样,如果pFreq[char]>=0,表明一个在p中的字符就要从窗口移动到p字符串中,那么count ++
if (pFreq[s.charAt(l++)]++ >= 0) {
count++; // one more needed to match
}
}
}
return ret;
}
}
参考:
标签:子串,count,ab,异位,字母,字符串 From: https://www.cnblogs.com/i9code/p/18007193