Find All Anagrams In A String

4 min read

Find all anagrams in a string is a classic problem that appears frequently in coding interviews, competitive programming, and real‑world text‑processing tasks. The goal is to locate every substring of a given text that is an anagram of a pattern string — meaning the substring contains exactly the same characters with the same frequencies, possibly in a different order. Solving this efficiently requires a blend of string manipulation, frequency counting, and sliding‑window techniques. Below you’ll find a thorough walk‑through that explains the concept, outlines several algorithmic strategies, provides step‑by‑step pseudocode, analyzes time and space complexity, and discusses practical applications Not complicated — just consistent..


Introduction

When you find all anagrams in a string, you are essentially scanning a larger body of text for every possible rearrangement of a smaller pattern. To give you an idea, given the text "cbaebabacd" and the pattern "abc", the anagrams appear at indices 0 ("cba"), 6 ("bac"), and 7 ("acd" is not an anagram, sorry—actually index 6 gives "bac" and index 0 gives "cba"; the correct indices are 0 and 6). Mastering this problem sharpens your ability to work with character frequency arrays, hash maps, and linear‑time scanning—skills that translate directly to tasks like DNA sequence analysis, plagiarism detection, and spell‑checking utilities.


Understanding Anagrams

An anagram is a word or phrase formed by rearranging the letters of another, using each original letter exactly once. In algorithmic terms, two strings s1 and s2 are anagrams iff:

  1. They have the same length.
  2. For every character c, the count of c in s1 equals the count of c in s2.

Thus, checking anagrams reduces to comparing frequency distributions rather than the actual ordering of characters.


Problem Statement

Input

  • A text string T of length n.
  • A pattern string P of length m (m ≤ n).

Output

  • A list of all starting indices i (0‑based) such that the substring T[i … i+m‑1] is an anagram of P.

If no such substring exists, return an empty list Simple, but easy to overlook..


Approaches to Solve the Problem

1. Brute‑Force Check

The simplest method enumerates every possible window of length m in T, sorts the characters inside the window, and compares the sorted window to the sorted pattern.

Steps

  1. Pre‑compute sortedP = sort(P).
  2. For each index i from 0 to n‑m:
    • Extract window = T[i:i+m].
    • If sort(window) == sortedP, record i.

Complexity

  • Time: O((n‑m+1) * m log m) due to sorting each window.
  • Space: O(m) for the temporary sorted window.

While easy to understand, this approach becomes impractical for large inputs because of the repeated sorting overhead.

2. Frequency‑Map Comparison (Naïve Sliding Window)

Instead of sorting, we can compare character frequency maps for each window.

Steps

  1. Build a frequency array/map freqP for the pattern (size = 26 for lowercase English letters, or a hash map for general Unicode).
  2. For each window start i:
    • Build a fresh frequency map freqWindow for T[i:i+m].
    • If freqWindow == freqP, add i to the answer.

Complexity

  • Time: O((n‑m+1) * m) because we rebuild the map from scratch each time.
  • Space: O(Σ) where Σ is the size of the character set (constant for ASCII).

This improves over brute force but still scans m characters per window.

3. Optimized Sliding Window with Incremental Updates

The optimal solution maintains a rolling frequency map as the window slides one character to the right, updating counts in O(1) per step And that's really what it comes down to..

Core Idea

  • Keep a frequency diff array diff[256] (or hash map) where diff[c] = count_in_window(c) - count_in_pattern(c).
  • The window is an anagram iff all entries in diff are zero.
  • Maintain a counter zeroCount that tracks how many entries are currently zero; when zeroCount == Σ, we have a match.

Algorithm

function findAnagrams(T, P):
    n ← length(T), m ← length(P)
    if m > n: return empty list

    // 1. Build frequency of pattern
    freqP[256] ← 0
    for ch in P:
        freqP[ch] ← freqP[ch] + 1

    // 2. Initialize window frequencies and diff
    diff[256] ← 0
    zeroCount ← 0
    for ch in alphabet:   // initialize diff as -freqP
        diff[ch] ← -freqP[ch]
        if diff[ch] == 0: zeroCount ← zeroCount + 1

    // 3. Add first m characters of T to the window
    for i from 0 to m‑1:
        ch ← T[i]
        if diff[ch] == 0: zeroCount ← zeroCount - 1   // will become non‑zero
        diff[ch] ← diff[ch] + 1
        if diff[ch] == 0: zeroCount ← zeroCount + 1   // became zero again

    result ← []
    if zeroCount == 256: result.append(0)

    // 4. Slide the window
    for i from m to n‑1:
        outCh ← T[i‑m]   // character leaving the window
        inCh  ← T[i]     // character entering the window

        // remove outCh
        if diff[outCh] == 0: zeroCount ← zeroCount - 1
        diff[outCh] ← diff[outCh] - 1
        if diff[outCh] == 0: zeroCount ← zeroCount + 1

        // add inCh
        if diff[inCh] == 0: zeroCount ← zeroCount - 1
        diff[inCh] ← diff[inCh] + 1
        if diff[inCh] == 0: zeroCount ← zeroCount + 1

        if zeroCount == 256:
            result.append(i‑m+1)

    return result
New Additions

Freshly Written

You Might Like

Related Reading

Thank you for reading about Find All Anagrams In A String. We hope the information has been useful. Feel free to contact us if you have any questions. See you next time — don't forget to bookmark!
⌂ Back to Home