Leetcode 438. Find All Anagrams in a String

题目

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

Example 2:

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

思路

我们先从最简单的情况开始思考:p中没有重复的字母。比如s = cbadeacb, p = abc. 这时我们可以运用HashSet保存p中的所有字母,用双指针遍历s中所有的substring。这里双指针为:left指向substring的开始,从s的开始一直走到s.length - p.length的位置,以检查s中的所有substring。对于每个left,right从left位置一直跑到left + p.length,以检查s中长度和p相同的substring是否是p的anagram。我们可以设一个count变量,以记录在substring中字母是p中字母的次数,如果count等于p.length,则说明我们找到了anagram.

p中有重复字母时,情况变得稍微复杂一些了。我们不仅需要记录p中每个字母出现的次数,还得检查在s的substring里面,是不是所有p里字母都出现了与p里相同的次数。前者可以通过HashMap来实现,以记录{char: frequency}。可是后者则较为麻烦。如果我们在检查某个substring的过程中对HashMap进行了修改,那么检查其他substring的时候结果就不会准确。这时我们需要运用sliding window的思想,在每次检查完一个substring后,并移动左指针的时,我们应该通过左指针来重置HashMap,以使HashMap正确表示p中字母及其频率。同时,因为right遇见合格字母时才改变count,left同样也只应该在遇见合格字母时重置count

解答

Complexity Analysis

  • Time Complexity: O(n). 我们的左右指针会以sliding window的方式各自遍历整个数组。

  • Space Complexity: O(1). 我们虽然使用了map来储存字母出现次数,但是由于字母个数的有限的(255),这个map只会占用constant space。

拓展

除了FindAnagram以外,我们还有很多类似的substring可以用类似的sliding windows的方法来解决。以下为这一大类问题的算法模板:

总结

Substring类问题核心在于如何找到substring、如何在过程中更新两头的指针、以及如何判断substring是否为valid。抓住以上几个要点后,我们则可以应用上面的通用算法思路,去解决细节不同但本质一样的各种substring类题目。

Reference

Last updated

Was this helpful?