LeetCode 438. Find All Anagrams in a String

Problem

LeetCode 438. Find All Anagrams in a String

1. 题目简述

给出两个字符串s和p,p非空,找出s中所有p的同字母异序词的索引。例如:

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".

2. 算法思路

sliding window

首先我们能想到的肯定是暴力破解,找出所有的长度和p相等的子串,然后判断是否和p的组成字符一致。可以AC,但是耗时过长,620ms,不太可取,因此尝试别的思路。

如何优化呢?其实我们每次去移动这个子串的时候,其实只移动了一位,剩余的完全没动,但是暴力搜索子串会做很多无意义的计算,因此耗时会变长,所以更加友好的方法应该去计算变化值。

3. 解法

  1. 暴力破解法,很多重复计算

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> result = new ArrayList();
        if (p.length() > s.length()) {
            return result;
        }

        int s_length = s.length(), p_length = p.length();
        char[] s_array = s.toCharArray();
        int[] src;
        int[] dest = new int[26];

        for (int i = 0; i < p_length; i++) {
            dest[p.charAt(i) - 'a']++;
        }

        for (int i = 0; i < s_length - p_length + 1; i++) {
            src = new int[26];
            for (int j = 0; j < p_length; j++) {
                src[s_array[i + j] - 'a']++;
            }
            int index = 0;
            boolean flag = true;
            while (index < 26 && flag) {
                if (src[index] != dest[index]) {
                    flag = false;
                    break;
                }
                index++;
            }
            if (flag){
                result.add(i);
            }
        }

         return result;
    }
}
  1. 记录变化值

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        if (p.length() > s.length()) {
            return new ArrayList<Integer>();
        }

        List<Integer> result = new ArrayList<Integer>();
        int s_length = s.length(), p_length = p.length();
        char[] char_s = s.toCharArray();
        char[] char_p = p.toCharArray();
        int[] arr_s = new int[26], arr_p = new int[26];

        for (int i = 0; i < p_length; i++) {
            arr_s[char_s[i] - 'a']++;
            arr_p[char_p[i] - 'a']++;
        }

        boolean flag = true;
        for (int i = 0; i < 26; i++) {
            if (arr_s[i] != arr_p[i]) {
                flag = false;
                break;
            }
        }
        if (flag) {
            result.add(0);
        }

        int start = 0, end = p_length - 1;
        while (end < s_length - 1) {
            arr_s[char_s[start] - 'a']--;
            start++;
            end++;
            arr_s[char_s[end] - 'a']++;
            flag = true;
            for (int i = 0; i < 26; i++) {
                if (arr_s[i] != arr_p[i]) {
                    flag = false;
                    break;
                }
            }
            if (flag) {
                result.add(start);
            }
        }

        return result;
    }
}