给定一个字符串 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" 的字母异位词。
答案
1public List<Integer> findAnagrams(String s, String p) {
2 List<Integer> list = new ArrayList<>();
3 if (s == null || s.length() == 0 || p == null || p.length() == 0)
4 return list;
5 int[] hash = new int[256];
6 for (char c : p.toCharArray()) {
7 hash[c]++;
8 }
9 int left = 0, right = 0, count = p.length();
10 while (right < s.length()) {
11 if (hash[s.charAt(right++)]-- >= 1)
12 count--;
13 if (count == 0)
14 list.add(left);
15 if (right - left == p.length() && hash[s.charAt(left++)]++ >= 0)
16 count++;
17 }
18 return list;
19}
解析:
先去判断前count个字母是否有异位词,如果有就添加到list中。然后在使用两个指针以间隔count的距离一前一后判断是否有异位词。题中说了只包含小写字母,还可以再改一下
1public List<Integer> findAnagrams(String s, String p) {
2 char[] ptrn = p.toCharArray();
3 char[] str = s.toCharArray();
4 int[] w = new int[26];
5 for (char c : ptrn) w[c - 'a']++;
6 int start = 0;
7 List<Integer> result = new LinkedList<>();
8 for (int i = 0; i < str.length; i++) {
9 int cIndex = str[i] - 'a';
10 w[cIndex]--;
11 while (w[cIndex] < 0) {
12 w[str[start] - 'a']++;
13 start++;
14 }
15 if (i - start + 1 == ptrn.length) {
16 result.add(start);
17 w[str[start] - 'a']++;
18 start++;
19 }
20 }
21 return result;
22}
或者
1public List<Integer> findAnagrams(String s, String p) {
2 int n = s.length(), i = 0;
3 List<Integer> result = new LinkedList<>();
4 int[] map = new int[26], pmap = toHash(p);
5 for (int j = 0; j < n; j++) {
6 map[s.charAt(j) - 'a']++;
7 while (j - i >= p.length()) {
8 map[s.charAt(i) - 'a']--;
9 i++;
10 }
11 if (Arrays.equals(map, pmap)) {
12 result.add(i);
13 }
14 }
15 return result;
16}
17
18private int[] toHash(String s) {
19 int[] map = new int[26];
20 for (char ch : s.toCharArray())
21 map[ch - 'a']++;
22 return map;
23}
在之前我们讲过 167,有效的字母异位词 ,也可以使用这种方式,通过截取每段,然后再进行判断
1public List<Integer> findAnagrams(String s, String p) {
2 List<Integer> res = new ArrayList<>();
3 if (p == null || s == null || s.length() < p.length()) return res;
4 int m = s.length(), n = p.length();
5 for (int i = 0; i < m - n + 1; i++) {
6 String cur = s.substring(i, i + n);
7 if (helper(cur, p)) res.add(i);
8 }
9 return res;
10}
11
12public boolean helper(String a, String b) {
13 if (a == null || b == null || a.length() != b.length()) return false;
14 int[] dict = new int[26];
15 for (int i = 0; i < a.length(); i++) {
16 char ch = a.charAt(i);
17 dict[ch - 'a']++;
18 }
19 for (int i = 0; i < b.length(); i++) {
20 char ch = b.charAt(i);
21 dict[ch - 'a']--;
22 if (dict[ch - 'a'] < 0) return false;
23 }
24 return true;
25}