Talentd
FleetCode
Make and follow sheets.Sign in

Find All Anagrams in a String solution and explanation

MediumHash TableSliding WindowString6 min read54.7% acceptanceUpdated 9 Apr 2026
Find All Anagrams in a String - Leetcode 438 - PythonNeetCode · 12:14 · 119K viewsWatch on YouTube
9 more videos on this problem
  1. Find All Anagrams in a String - Leetcode 438 - PythonNeetCode · 12:14 · 119K views
  2. Find All Anagrams in a String | Sliding window | Leetcode #438Techdose · 8:50 · 83K views
  3. LeetCode 438. Find All Anagrams in a String (Algorithm Explained)Nick White · 10:48 · 65K views
  4. Find all anagrams in a string (LeetCode 438) | Sliding window approach with animationsNikhil Lohia · 15:24 · 17K views
  5. 438. Find All Anagrams in a String | JavaScript | Sliding Window | 2 Pointer | Daily ChallengeLeetCodeWithMonu · 11:14 · 1K views
  6. Find all anagrams in a string | leetcode 438 solutionMaZee Tech · 12:28 · 1K views
  7. Find All Anagrams in a String - LeetCode 438 - Python - Visually ExplainedHello Byte · 5:18 · 1K views
  8. FIND ALL ANAGRAMS IN STRING | LEETCODE 438 | PYTHON SLIDING WINDOW SOLUTIONCracking FAANG · 10:38 · 946 views
  9. Leetcode Solution - 438 Find All Anagrams in a StringJohn Leonardo · 12:04 · 685 views
  10. Daily Leetcode #673: Feb 02, 2022 - 438. Find All Anagrams in a StringProgramming Live with Larry · 9:43 · 262 views

The problem

Given two strings s and p, return an array of all the start indices of p's anagrams in s. You may return the answer in any order.

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

Constraints:

  • 1 <= s.length, p.length <= 3 * 104
  • s and p consist of lowercase English letters.

Approach overview

Problem Overview: Given a string s and a pattern p, return all starting indices in s where the substring is an anagram of p. Two strings are anagrams if they contain the same characters with the same frequency, just in a different order.

Approach 1: Sliding Window with Character Count (O(n) time, O(1) space)

This approach uses a fixed-size sliding window equal to the length of p. Maintain two frequency counters: one for the pattern and one for the current window in s. As the window moves one character at a time, increment the count for the incoming character and decrement the count for the outgoing character. When both frequency arrays match, the window represents an anagram and its starting index is recorded.

The key insight is that the window size never changes. Each step performs constant-time updates on a small character frequency array (typically size 26 for lowercase letters). This makes the entire scan linear. This technique is a classic application of the sliding window pattern combined with frequency counting.

Because the alphabet size is fixed, the extra memory remains constant, giving O(1) space complexity. This method is efficient and commonly expected in interviews for substring-anagram problems.

Approach 2: HashMap with Two-Pointer Technique (O(n) time, O(k) space)

This version uses a hash table to track character frequencies of the pattern and applies a dynamic window using two pointers (left and right). Expand the right pointer while updating counts in the map. When a character exceeds the required frequency, move the left pointer forward to restore a valid window.

Whenever the window length equals the pattern length and the frequency constraints are satisfied, the current left index is an anagram start. The two-pointer structure ensures each character is processed at most twice—once when entering the window and once when leaving.

This method generalizes well when the character set is larger than lowercase letters. Instead of fixed arrays, the frequency structure is stored in a map, making it flexible for arbitrary strings. It combines ideas from string processing and hash-based frequency tracking.

Recommended for interviews: The sliding window with character count is the most direct and commonly expected solution. It demonstrates understanding of fixed-window substring problems and achieves optimal O(n) time with constant space. Implementing the hashmap + two-pointer version also shows strong control over window management and frequency tracking. Interviewers usually accept either, but the fixed sliding window is typically the cleanest implementation.

Approach 1: Sliding Window with Character Count

This approach utilizes a sliding window technique combined with character count comparisons to efficiently find all anagrams of the string p within the string s. By maintaining a window of length equal to p as we iterate through s, and by checking the frequency of characters within this window with the frequency of characters in p, we can determine if the substring is an anagram.

def findAnagrams(s, p):
    from collections import Counter
    p_count = Counter(p)
    s_count = Counter(s[:len(p) - 1])
    result = []

    for i in range(len(p) - 1, len(s)):
        s_count[s[i]] += 1  # Include the new character in the window
        if s_count == p_count:  # Compare window with p
            result.append(i - len(p) + 1)  # Append the start index
        s_count[s[i - len(p) + 1]] -= 1  # Remove the character sliding out of the window
        if s_count[s[i - len(p) + 1]] == 0:
            del s_count[s[i - len(p) + 1]]  # Clean up the count dictionary

    return result
function findAnagrams(s, p) {
    const pCount = new Array(26).fill(0);
    const sCount = new Array(26).fill(0);
    const result = [];
    const aCharCode = 'a'.charCodeAt(0);

    for (const char of p) {
        pCount[char.charCodeAt(0) - aCharCode]++;
    }
    
    for (let i = 0; i < s.length; i++) {
        sCount[s[i].charCodeAt(0) - aCharCode]++;

        if (i >= p.length) {
            sCount[s[i - p.length].charCodeAt(0) - aCharCode]--;
        }

        if (arraysEqual(pCount, sCount)) {
            result.push(i - p.length + 1);
        }
    }
    return result;
}

function arraysEqual(arr1, arr2) {
    for (let i = 0; i < 26; i++) {
        if (arr1[i] !== arr2[i]) return false;
    }
    return true;
}

This Python solution initializes a counter for the string p and a sliding window counter for s of length equivalent to p. As the window slides over s, we update the count of characters within this window. If the window's character frequency matches with that of p, it implies an anagram is found and we record the starting index.

Complexity

Time Complexity: O(n) where n is the length of s, because we iterate over `s` once.
Space Complexity: O(1) since the size of the character frequency array is fixed with respect to the alphabet.

Try this approach in the editor

Approach 2: Hashmap with Two-pointer Technique

This approach leverages hashmaps (or dictionaries) and a two-pointer technique to find the anagrams of p in s. We maintain counts of characters using hashmaps and adjust them as the two pointers traverse through s.

import java.util.*;

public class Solution {
    public List<Integer> findAnagrams(String s, String p) {
        List<Integer> result = new ArrayList<>();
        if (p.length() > s.length()) return result;

        int[] pCount = new int[26];
        int[] sCount = new int[26];

        for (char c : p.toCharArray()) {
            pCount[c - 'a']++;
        }

        for (int i = 0; i < s.length(); i++) {
            sCount[s.charAt(i) - 'a']++;

            if (i >= p.length()) {
                sCount[s.charAt(i - p.length()) - 'a']--;
            }

            if (Arrays.equals(pCount, sCount)) {
                result.add(i - p.length + 1);
            }
        }
        return result;
    }
}
#include <vector>
#include <string>
#include <unordered_map>
using namespace std;

vector<int> findAnagrams(string s, string p) {
    unordered_map<char, int> p_count, s_count;
    vector<int> result;
    int pl = p.size(), sl = s.size();

    if (pl > sl) return result;

    for (int i = 0; i < pl; i++) {
        p_count[p[i]]++;
        s_count[s[i]]++;
    }

    for (int i = pl; i < sl; i++) {
        if (p_count == s_count) {
            result.push_back(i - pl);
        }
        s_count[s[i]]++;
        s_count[s[i - pl]]--;
        if (s_count[s[i - pl]] == 0) {
            s_count.erase(s[i - pl]);
        }
    }

    if (p_count == s_count) {
        result.push_back(sl - pl);
    }
    return result;
}

This Java approach employs two arrays to store the frequency of each character. We iterate over s with a sliding window of size equal to p, updating these arrays accordingly. If both frequency arrays match at any point, it indicates the presence of an anagram.

Complexity

Time Complexity: O(n) where n is the length of `s`.
Space Complexity: O(1) since we use a fixed-size frequency array of 26.

Try this approach in the editor

Approach 3: Default Approach

function findAnagrams(s: string, p: string): number[] {
    const m = s.length;
    const n = p.length;
    const ans: number[] = [];
    if (m < n) {
        return ans;
    }
    const cnt1: number[] = new Array(26).fill(0);
    const cnt2: number[] = new Array(26).fill(0);
    const idx = (c: string) => c.charCodeAt(0) - 'a'.charCodeAt(0);
    for (const c of p) {
        ++cnt1[idx(c)];
    }
    for (const c of s.slice(0, n - 1)) {
        ++cnt2[idx(c)];
    }
    for (let i = n - 1; i < m; ++i) {
        ++cnt2[idx(s[i])];
        if (cnt1.toString() === cnt2.toString()) {
            ans.push(i - n + 1);
        }
        --cnt2[idx(s[i - n + 1])];
    }
    return ans;
}
public class Solution {
    public IList<int> FindAnagrams(string s, string p) {
        int m = s.Length, n = p.Length;
        IList<int> ans = new List<int>();
        if (m < n) {
            return ans;
        }
        int[] cnt1 = new int[26];
        int[] cnt2 = new int[26];
        for (int i = 0; i < n; ++i) {
            ++cnt1[p[i] - 'a'];
        }
        for (int i = 0, j = 0; i < m; ++i) {
            int k = s[i] - 'a';
            ++cnt2[k];
            while (cnt2[k] > cnt1[k]) {
                --cnt2[s[j++] - 'a'];
            }
            if (i - j + 1 == n) {
                ans.Add(j);
            }
        }
        return ans;
    }
}
func findAnagrams(s string, p string) (ans []int) {
	m, n := len(s), len(p)
	if m < n {
		return
	}
	cnt1 := [26]int{}
	cnt2 := [26]int{}
	for _, c := range p {
		cnt1[c-'a']++
	}
	for _, c := range s[:n-1] {
		cnt2[c-'a']++
	}
	for i := n - 1; i < m; i++ {
		cnt2[s[i]-'a']++
		if cnt1 == cnt2 {
			ans = append(ans, i-n+1)
		}
		cnt2[s[i-n+1]-'a']--
	}
	return
}
impl Solution {
    pub fn find_anagrams(s: String, p: String) -> Vec<i32> {
        let (s, p) = (s.as_bytes(), p.as_bytes());
        let (m, n) = (s.len(), p.len());
        let mut ans = vec![];
        if m < n {
            return ans;
        }

        let mut cnt = [0; 26];
        for i in 0..n {
            cnt[(p[i] - b'a') as usize] += 1;
            cnt[(s[i] - b'a') as usize] -= 1;
        }
        for i in n..m {
            if cnt.iter().all(|&v| v == 0) {
                ans.push((i - n) as i32);
            }
            cnt[(s[i] - b'a') as usize] -= 1;
            cnt[(s[i - n] - b'a') as usize] += 1;
        }
        if cnt.iter().all(|&v| v == 0) {
            ans.push((m - n) as i32);
        }
        ans
    }
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Sliding Window with Character Count

Time Complexity: O(n) where n is the length of s, because we iterate over `s` once.
Space Complexity: O(1) since the size of the character frequency array is fixed with respect to the alphabet.

Hashmap with Two-pointer Technique

Time Complexity: O(n) where n is the length of `s`.
Space Complexity: O(1) since we use a fixed-size frequency array of 26.

Default Approach–

Complexity analysis

ApproachTimeSpaceWhen to Use
Sliding Window with Character CountO(n)O(1)Best choice when characters are limited (e.g., lowercase letters) and a fixed-size window works.
HashMap with Two-Pointer TechniqueO(n)O(k)Useful when the character set is large or dynamic and array indexing is not practical.

Frequently asked questions

Is Find All Anagrams in a String easy or hard?

Find All Anagrams in a String is generally classified as a medium-level problem. The main challenge is recognizing the sliding window pattern and managing character frequency updates efficiently.

Find All Anagrams in a String Python/Java solution

Python solutions typically use a list of size 26 for character counts and implement a sliding window across the string. Java solutions often use either integer arrays or HashMap-based frequency tracking with two pointers. Both approaches achieve O(n) time complexity.

How to solve Find All Anagrams in a String in O(n)?

Use a sliding window of size equal to the pattern length and maintain character frequency counts for both the pattern and the current window. Move the window one step at a time, updating counts for entering and leaving characters. When both frequency counts match, record the starting index. This processes the string in a single pass.

What is the best approach for Find All Anagrams in a String?

The sliding window with character frequency counting is the most efficient approach. Maintain a window of length equal to the pattern and update counts as the window moves across the string. Matching frequency arrays indicate an anagram. This runs in O(n) time with O(1) extra space for fixed alphabets.

Is Find All Anagrams in a String asked at Google/Amazon/Meta?

Find All Anagrams in a String is a common interview problem at large tech companies including Amazon, Meta, and Google. It tests understanding of sliding window techniques, frequency counting, and efficient substring processing.

What data structure is used in Find All Anagrams in a String?

The main data structures are frequency arrays or hash maps that store character counts. These structures allow constant-time updates and comparisons while the sliding window moves across the string.

What is the time complexity of Find All Anagrams in a String?

The optimal solution runs in O(n) time, where n is the length of the string. Each character is processed once as the sliding window expands and contracts. Frequency updates and comparisons are constant time when using a fixed-size array.

Comments

Now write it yourselfClose this page and solve Find All Anagrams in a String in the editor, without looking.
Practise Find All Anagrams in a String