Find All Anagrams in a String

May 17, 2020

Introduction

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

Solution

We need somehowe to build a map of occur letters in pattern, ideally by using array with fixed size 26, because of lowercase English letters. And then, by using sliding window calculate occurency map for incoming string and compare each time with pattern one.

func findAnagrams(s string, p string) []int {
    var out []int
    ss, pp := []byte(s), []byte(p)
    n, m := len(ss), len(pp)
    if n < m || m == 0 {
        return out
    }
    var check,dp [26]int
    for _, ch := range pp {
        check[ch-'a']++
    }
    for _, ch := range ss[:m] {
        dp[ch-'a']++
    }
    if equal(check[:], dp[:], 26) {
        out = []int {0}    
    }
    for i := m; i < n; i++ {
        dp[ss[i-m]-'a']--   
        dp[ss[i]-'a']++  
        if equal(check[:], dp[:], 26) {
            out = append(out, i-m+1)  
        }
    }
    return out
}

func equal(a, b []int, n int) bool {
    for i := 0; i < n; i++ {
        if a[i] != b[i] {
            return false
        }
    }
    return true
}

Performance

Hard to make better:

Runtime: 0 ms
Memory Usage: 5.3 MB

comments powered by Disqus

Do you want to know me more private?→Click!