力扣打卡:438. 找到字符串中所有字母异位词
解题思路
思路挺多的,最重要的还是映射到数组上,进行统计
因为给定的字符就是26
的小写字母,那么直接生成一个26
长度的数组,数组元素是对应字符串p
的字符个数
- 对
s
进行遍历 - 遍历一个元素,那么将对应的
arr
的元素--arr[c-'a']
进行递减,然后判断是否小于0
- 如果小于
0
- 判断此时的字符串
p
是否包含这个字符- 如果不包含,那么在这个字符
c
之前的就不再有可能生成异位词了- 检查字符的数组元素是否全部为
0
,如果全部为0
,那么是一个异位词,如果不是,那么不是异位词 - 索引从字符
c
的下一个字符开始
- 检查字符的数组元素是否全部为
- 如果包含
- 检查此时的元素是否还有大于
0
的,如果没有,那么也是一个答案 - 索引重新定位到此时
c
字符的倒数算第n
个的c
字符,这个字符也是c
,只统计c
这个字符的个数,统计的个数是n
,也就是字符串p
中的c
个数
- 检查此时的元素是否还有大于
- 如果不包含,那么在这个字符
- 判断此时的字符串
- 如果不小于
0
,那么索引一直递增
代码
class Solution {
public List<Integer> findAnagrams(String s, String p) {
HashSet<Character> set = new HashSet<>();
List<Integer> ans = new ArrayList<>();
int[] arr = new int[26];
int[] copy = new int[26];
for(char c : p.toCharArray()) {arr[c-'a']++; set.add(c);};
System.arraycopy(arr,0,copy,0,26); // 将数组保存下来
int idx = 0;
int len = s.length();
while(idx < len){
char c = s.charAt(idx);
if(--arr[c-'a'] < 0){
if(set.contains(c)){
boolean hasOther = false;
for(int x: arr) if(x>0){hasOther = true; break;}
if(!hasOther){ans.add(idx-p.length());}
idx = back(s, c, idx-1,copy[c-'a']); // 从idx开始向左边匹配
}else{ // 如果p中不包含这个字符,那么检查arr中是否还有元素大于0
boolean hasOther = false;
for(int x: arr) if(x>0){hasOther = true; break;}
if(hasOther){ // 如果含有非0的元素
idx++;
}else{ // 如果元素都是0,那么是一个异位字符
ans.add(idx-p.length());
}
}
System.arraycopy(copy,0,arr,0,26); // 将数组重新置位,新一轮的开始
continue;
}
idx++;
}
boolean hasOther = false;
for(int x : arr) if(x>0) return ans;
ans.add(s.length()-p.length());
return ans;
}
public int back(String s, char c, int p, int count){
int cnt = 0;
while( p>=0 ){
if(s.charAt(p)==c) cnt++;
if(cnt==count) break;
p--;
}
return ++p; // 因为此时的字符c的个数已经小于0,所以从这个字符的下一个字符开始匹配
}
}