Star

LeetCode 438. Find All Anagrams in a String

Question:

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:

1
2
3
4
5
6
7
8
9
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:

1
2
3
4
5
6
7
8
9
10
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".

Explanation

暴力解会超时。需要采用sliding window的方法。 参照 https://discuss.leetcode.com/topic/64434/shortest-concise-java-o-n-sliding-window-solution 另外还有一些总结的模板: https://discuss.leetcode.com/topic/30941/here-is-a-10-line-template-that-can-solve-most-substring-problems

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public List<Integer> findAnagrams(String s, String p) {
List<Integer> list = new ArrayList<>();
if(s == null || p == null || s.length() < p.length()) return list;
int[] chars = new int[256];
for(Character c:p.toCharArray()) {
chars[c] ++;
}
int start = 0; int end = 0; int count = p.length();
while(end < s.length()) {
//move right everytime, if the character exists in p's hash, decrease the count
//current hash value >= 1 means the character is existing in p
if (chars[s.charAt(end)] >= 1) {
count--;
}
chars[s.charAt(end)]--;
end++;
//when the count is down to 0, means we found the right anagram
//then add window's left to result list
if (count == 0) {
list.add(start);
}
//if we find the window's size equals to p, then we have to move left (narrow the window) to find the new match window
//++ to reset the hash because we kicked out the left
//only increase the count if the character is in p
//the count >= 0 indicate it was original in the hash, cuz it won't go below 0
if (end - start== p.length() ) {
if (chars[s.charAt(start)] >= 0) {
count++;
}
chars[s.charAt(start)]++;
start++;
}
}
return list;
}