给定一个字符串 和一个非空字符串 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}