NOTE

Find All Anagrams in a String

Find all anagrams in a string using brute force and a sliding window with counts.

Data Structures & AlgorithmsCreated Updated 1 min readhistorical

This is a historical learning note and may contain outdated or incomplete understanding.

1. Problem Description

Given a string s and a non-empty string p, find all substrings in s that are anagrams of p and return their starting indexes.

2. Approach

  • Brute force
  • Sliding window + counting

3. Implementation

3.1. Brute Force

import "sort"

func findAnagrams(s string, p string) []int {
	if len(s) < len(p) {
		return nil
	}

	pRunes := []rune(p)
	sort.Slice(pRunes, func(i, j int) bool {
		return pRunes[i] < pRunes[j]
	})
	p = string(pRunes)

	res := make([]int, 0)
	sRunes := []rune(s)
	for i := 0; i < len(sRunes)-len(pRunes)+1; i++ {
		dst := make([]rune, len(pRunes))
		copy(dst, sRunes[i:i+len(pRunes)])
		sort.Slice(dst, func(i, j int) bool {
			return dst[i] < dst[j]
		})
		if string(dst) == p {
			res = append(res, i)
		}
	}
	return res
}

3.2. Sliding Window + Counting

func findAnagrams2(s string, p string) []int {
	if len(s) < len(p) {
		return nil
	}

	// Count the occurrences of each letter
	pCnt := make([]int, 26)
	sCnt := make([]int, 26)
	for i := 0; i < len(p); i++ {
		pCnt[p[i]-'a']++
		sCnt[s[i]-'a']++
	}

	// Check whether the first position matches
	res := make([]int, 0)
	if reflect.DeepEqual(sCnt, pCnt) {
		res = append(res, 0)
	}

	// Check the remaining positions
	for i := len(p); i < len(s); i++ {
		sCnt[s[i-len(p)]-'a']--
		sCnt[s[i]-'a']++
		if reflect.DeepEqual(sCnt, pCnt) {
			res = append(res, i-len(p)+1)
		}
	}

	return res

}

4. References

Discussion

Sign in with GitHub to comment. Discussions are stored as GitHub Issues.View on GitHub