Find All Anagrams in a String

Return all start indices of `p`'s anagrams in `s` — sliding window of letter counts.

Medium
Time O(N) Space O(1)
LeetCode
6 min read
sliding-window hash-map strings

Problem#

Given strings s and p, return all start indices of substrings in s that are anagrams of p.

Examples#

  • s = "cbaebabacd", p = "abc"[0,6].
  • s = "abab", p = "ab"[0,1,2].

Constraints#

  • 1 <= s.length, p.length <= 3 * 10^4, lowercase letters.

Hints#

Hint
Slide a window of length |p| over s. Use a counter difference; track how many letters are still “off”.

Approach#

Maintain need[26] from p and a sliding window over s. Track a matches counter — how many letters in the window match need exactly. Slide by adding the right and removing the left; update matches incrementally. Record i - |p| + 1 whenever matches == 26.

Solution#

Find All Anagrams in a String
class Solution {
public:
vector<int> findAnagrams(string s, string p) {
int n = s.size(), m = p.size();
vector<int> ans;
if (n < m) return ans;
int need[26] = {0}, have[26] = {0};
for (char c : p) ++need[c - 'a'];
int matched = 0;
for (int i = 0; i < 26; ++i) if (need[i] == 0) ++matched;
for (int i = 0; i < n; ++i) {
int add = s[i] - 'a';
++have[add];
if (have[add] == need[add]) ++matched;
else if (have[add] == need[add] + 1) --matched;
if (i >= m) {
int rem = s[i - m] - 'a';
--have[rem];
if (have[rem] == need[rem]) ++matched;
else if (have[rem] == need[rem] - 1) --matched;
}
if (matched == 26) ans.push_back(i - m + 1);
}
return ans;
}
};

Editorial#

The matches counter avoids O(26) comparison per slide. We increment when a letter’s count first equals need, decrement when it exceeds need, and symmetrically on removal. Once matches == 26 (all 26 letters in correct count), the window is an anagram.

Complexity#

  • Time: O(N).
  • Space: O(1).

Concept revision#

Search ESC

Keyboard shortcuts

Shortcuts are disabled while typing in inputs.