Find All Anagrams in a String

MediumSliding Window · Fixed Size🧩 Sliding WindowLeetCode #438 ↗Updated

Problem

Given strings s and p of lowercase letters, return every index i where the substring of s starting at i with length |p| is an anagram of p (same letters, same counts, any order). The indices may be returned in any order.
Inputs="cbaebabacd", p="abc"Output[0,6]
Inputs="abab", p="ab"Output[0,1,2]

1 ≤ |s|, |p| ≤ 3·104  ·  lowercase English letters only

Try it yourself

Java
class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
Every candidate has the same length |p|, so use a fixed-size sliding window: moving one step changes only two letter counts. Track how many letters of p are still missing to test a window in O(1).
PatternSliding Window

Instinct Longest, shortest or count of contiguous subarrays/substrings meeting a rule? Grow a window on the right, shrink it on the left, never step back.

Memory hack Move like a caterpillar - the head stretches forward to grab, the tail pulls up only when the body breaks the rule.

Open the Sliding Window guide →

Approaches

Brute ForceSort Every Window

Time O(n · m log m)Space O(m)

Two strings are anagrams iff their sorted forms are equal. Sort p once, then sort each length-m window of s (n = |s|, m = |p|) and compare.

Java
public List<Integer> findAnagrams(String s, String p) {
    List<Integer> res = new ArrayList<>();
    char[] target = p.toCharArray();
    Arrays.sort(target);
    for (int i = 0; i + p.length() <= s.length(); i++) {
        char[] win = s.substring(i, i + p.length()).toCharArray();
        Arrays.sort(win);
        if (Arrays.equals(win, target)) res.add(i);
    }
    return res;
}

Simple, but re-sorts overlapping windows — slow when m is large.

At a glance

LevelApproachTimeSpace
Brute ForceSort Every WindowO(n · m log m)O(m)
BetterSliding Window + Two Count ArraysO(m + 26·n)O(1)
OptimalSliding Window + Missing CounterO(n + m)O(1)
Common pitfalls
  • Not handling |p| > |s| — the brute force loop bound must be i + m ≤ n.
  • Removing s[i-m+1] instead of s[i-m] — window shrinks to m-1.
  • Using a variable-size window (shrink on mismatch) — anagram windows are always exactly m long.
Interview tips
  • Confirm the alphabet: 26 lowercase letters allows int[26] instead of a map.
  • Start with the two-array window, then optimise the comparison with a counter.
  • Point out that Permutation in String (567) is the same check returning a boolean.
Pattern
Fixed-size sliding window + frequency counts → find all windows that are permutations of a pattern.
My notes saved in this browser