leetcode438

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

Map. O(n)
理解题意:明确anagram的本质是字符的统计频次一致。所以用Map<Character, Integer>统计字符频次。发现频次吻合的时候就是找到anagram的时候。
1.一开始统计一遍对比物p的字符频次,注意按负数统计。
2.开始扫描字符串s。在中间的general case的时候,入新的字符的统计,出最远字符的统计。(这样可以做到O(1)时间而不是p.length()时间)
3.检查是不是抵消吻合让map的size()变0了。(用size()==0来判断也是为了降低时间复杂度,如果维护两个map,每次要靠确认是不是每个char的count都一致的话要浪费O(p.length())时间。

细节:
1.count == 0的时候要remove一下,不然不能保证size()归0。

实现:

class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> ans = new ArrayList<>();
        Map<Character, Integer> map = new HashMap<>();
        char[] cs = s.toCharArray();
        
        for (char c : p.toCharArray()) {
            map.put(c, map.getOrDefault(c, 0) - 1);
        }
        
        for (int i = 0; i < s.length(); i++) {
            map.put(cs[i], map.getOrDefault(cs[i], 0) + 1);
            if (map.get(cs[i]) == 0) {
                map.remove(cs[i]);
            }
            if (i >= p.length()) {
                map.put(cs[i - p.length()], map.getOrDefault(cs[i - p.length()], 0) - 1);
                if (map.get(cs[i - p.length()]) == 0) {
                    map.remove(cs[i - p.length()]);
                }
            }
            if (map.size() == 0) {
                ans.add(i - p.length() + 1);
            }
        }
        
        return ans;
    }
}
原文地址:https://www.cnblogs.com/jasminemzy/p/9627134.html