Given a string s and a non-empty string p, find all the start indices of p's anagrams in s.
Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than 20,100.
The order of output does not matter.
Example 1:
Input: s: "cbaebabacd" p: "abc" Output: [0, 6] Explanation: The substring with start index = 0 is "cba", which is an anagram of "abc". The substring with start index = 6 is "bac", which is an anagram of "abc".
Example 2:
Input: s: "abab" p: "ab" Output: [0, 1, 2] Explanation: The substring with start index = 0 is "ab", which is an anagram of "ab". The substring with start index = 1 is "ba", which is an anagram of "ab". The substring with start index = 2 is "ab", which is an anagram of "ab".
解析:给定两个字符串,s为主串,p为子串,求出s中包含p的同字母异次序的所有起始位置。其中题目的要求是:在s中子串的字母必须和p的字母种类和数量保持一致,无顺序要求。因此我们可以统计p中字符的出现次数,然后在s中从头开始遍历,每次在s中找p字符串长度个字符,然后验证字符个数是否相等。
具体过程:定义一个长度为256的hash数组(ascii码范围),数组的索引表示字符的ascii值,记录p中字符出现的次数。然后定义两个变量left和right表示滑动窗口的左右边界,定义变量count表示字符串p中需要匹配的字符个数(即p的长度)。然后开始遍历s,在窗口右移过程中,如果right位置的字符已经在哈希表中了,说明该字符在p中有出现,则count减1,然后哈希表中该字符个数自减1,右边界right加1;如果此时count等于0,说明p中的字符在s的子串中都匹配上了,那么将此时左边界left加入结果res中;如果此时right和left的差为p的长度,说明此时应该去掉最左边的一个字符,我们看如果该字符在哈希表中的个数大于等于0,说明该字符是p中的字符。因为上面我们有让每个字符减1,如果不是p中的字符,那么在哈希表中个数应该为0,自减1后就为-1,所以这样就知道该字符是否属于p,如果我们去掉了属于p的一个字符,count自增1。
public class FindAllAnagramsinaString438 {
public static void main(String[] args) {
String s = "cbaebabacd";
String p = "abc";
System.out.println(findAnagrams(s, p));
}
public static List<Integer> findAnagrams(String s, String p) {
ArrayList<Integer> res = new ArrayList<Integer>();
// 定义hash表
int[] hash = new int[256];
for(int i=0;i<p.length();i++){
hash[p.charAt(i)]++;
}
int left=0;
int right=0;
int count=p.length();
while(right<s.length()){
// 窗口右移,相应的hash值减小,如果这个位置的Hash值是正的,
// 表示p字符串也包含这个, 所以count--
if(hash[s.charAt(right++)]-->0) count--;
// count为0表示s的子串和p对应的hash值完全一致
if(count==0) res.add(left);
// 如果当窗口大小一定的时候即窗口大小和需要比较的字符串大小一致的时候
// 将窗口左边的指针向右边移动,移动的同时左边的字符计数因为在第一个if的地方hash值减小过
// 所以需要执行对应恢复操作,即:hash值增加,count值增加
if(right-left==p.length()&&hash[s.charAt(left++)]++>=0) count++;
}
return res;
}
}