LeetCodee

438. Find All Anagrams in a String

Jump to Solution: Python Java C++ JavaScript C#

Problem Description

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.

An Anagram is a word or phrase formed by rearranging the letters of a different word or phrase, typically using all the original letters exactly once.

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 * 10⁴
  • s and p consist of lowercase English letters.

Solution

Python Solution

class Solution:
    def findAnagrams(self, s: str, p: str) -> List[int]:
        if len(p) > len(s):
            return []
        
        # Initialize frequency counters
        p_count = Counter(p)
        window_count = Counter()
        result = []
        
        # Process first window
        for i in range(len(p)):
            window_count[s[i]] += 1
        
        # Check first window
        if window_count == p_count:
            result.append(0)
        
        # Slide window and check remaining positions
        for i in range(len(p), len(s)):
            # Add new character
            window_count[s[i]] += 1
            # Remove old character
            window_count[s[i - len(p)]] -= 1
            
            # Remove count if zero
            if window_count[s[i - len(p)]] == 0:
                del window_count[s[i - len(p)]]
            
            # Check if current window is anagram
            if window_count == p_count:
                result.append(i - len(p) + 1)
        
        return result

Time Complexity: O(n)

Where n is the length of string s.

Space Complexity: O(k)

Where k is the size of the character set (26 for lowercase English letters).

Java Solution

class Solution {
    public List findAnagrams(String s, String p) {
        if (p.length() > s.length()) {
            return new ArrayList<>();
        }
        
        // Initialize frequency arrays
        int[] pCount = new int[26];
        int[] windowCount = new int[26];
        List result = new ArrayList<>();
        
        // Count frequencies in p
        for (char c : p.toCharArray()) {
            pCount[c - 'a']++;
        }
        
        // Process first window
        for (int i = 0; i < p.length(); i++) {
            windowCount[s.charAt(i) - 'a']++;
        }
        
        // Check first window
        if (Arrays.equals(windowCount, pCount)) {
            result.add(0);
        }
        
        // Slide window and check remaining positions
        for (int i = p.length(); i < s.length(); i++) {
            // Add new character
            windowCount[s.charAt(i) - 'a']++;
            // Remove old character
            windowCount[s.charAt(i - p.length()) - 'a']--;
            
            // Check if current window is anagram
            if (Arrays.equals(windowCount, pCount)) {
                result.add(i - p.length() + 1);
            }
        }
        
        return result;
    }
}

Time Complexity: O(n)

Where n is the length of string s.

Space Complexity: O(1)

Using fixed-size arrays for character frequencies.

C++ Solution

class Solution {
public:
    vector findAnagrams(string s, string p) {
        if (p.length() > s.length()) {
            return {};
        }
        
        // Initialize frequency arrays
        vector pCount(26, 0);
        vector windowCount(26, 0);
        vector result;
        
        // Count frequencies in p
        for (char c : p) {
            pCount[c - 'a']++;
        }
        
        // Process first window
        for (int i = 0; i < p.length(); i++) {
            windowCount[s[i] - 'a']++;
        }
        
        // Check first window
        if (windowCount == pCount) {
            result.push_back(0);
        }
        
        // Slide window and check remaining positions
        for (int i = p.length(); i < s.length(); i++) {
            // Add new character
            windowCount[s[i] - 'a']++;
            // Remove old character
            windowCount[s[i - p.length()] - 'a']--;
            
            // Check if current window is anagram
            if (windowCount == pCount) {
                result.push_back(i - p.length() + 1);
            }
        }
        
        return result;
    }
};

Time Complexity: O(n)

Where n is the length of string s.

Space Complexity: O(1)

Using fixed-size vectors for character frequencies.

JavaScript Solution

/**
 * @param {string} s
 * @param {string} p
 * @return {number[]}
 */
var findAnagrams = function(s, p) {
    if (p.length > s.length) {
        return [];
    }
    
    // Initialize frequency maps
    const pCount = new Map();
    const windowCount = new Map();
    const result = [];
    
    // Count frequencies in p
    for (const c of p) {
        pCount.set(c, (pCount.get(c) || 0) + 1);
    }
    
    // Process first window
    for (let i = 0; i < p.length; i++) {
        windowCount.set(s[i], (windowCount.get(s[i]) || 0) + 1);
    }
    
    // Check first window
    if (mapsEqual(windowCount, pCount)) {
        result.push(0);
    }
    
    // Slide window and check remaining positions
    for (let i = p.length; i < s.length; i++) {
        // Add new character
        windowCount.set(s[i], (windowCount.get(s[i]) || 0) + 1);
        // Remove old character
        const oldChar = s[i - p.length];
        windowCount.set(oldChar, windowCount.get(oldChar) - 1);
        if (windowCount.get(oldChar) === 0) {
            windowCount.delete(oldChar);
        }
        
        // Check if current window is anagram
        if (mapsEqual(windowCount, pCount)) {
            result.push(i - p.length + 1);
        }
    }
    
    return result;
};

function mapsEqual(map1, map2) {
    if (map1.size !== map2.size) {
        return false;
    }
    for (const [key, value] of map1) {
        if (map2.get(key) !== value) {
            return false;
        }
    }
    return true;
}

Time Complexity: O(n)

Where n is the length of string s.

Space Complexity: O(k)

Where k is the size of the character set.

C# Solution

public class Solution {
    public IList FindAnagrams(string s, string p) {
        if (p.Length > s.Length) {
            return new List();
        }
        
        // Initialize frequency arrays
        int[] pCount = new int[26];
        int[] windowCount = new int[26];
        IList result = new List();
        
        // Count frequencies in p
        foreach (char c in p) {
            pCount[c - 'a']++;
        }
        
        // Process first window
        for (int i = 0; i < p.Length; i++) {
            windowCount[s[i] - 'a']++;
        }
        
        // Check first window
        if (Enumerable.SequenceEqual(windowCount, pCount)) {
            result.Add(0);
        }
        
        // Slide window and check remaining positions
        for (int i = p.Length; i < s.Length; i++) {
            // Add new character
            windowCount[s[i] - 'a']++;
            // Remove old character
            windowCount[s[i - p.Length] - 'a']--;
            
            // Check if current window is anagram
            if (Enumerable.SequenceEqual(windowCount, pCount)) {
                result.Add(i - p.Length + 1);
            }
        }
        
        return result;
    }
}

Time Complexity: O(n)

Where n is the length of string s.

Space Complexity: O(1)

Using fixed-size arrays for character frequencies.

Approach Explanation

The solution uses a sliding window approach with character frequency counting:

  1. Key Insights:
    • Sliding window
    • Character frequency
    • Window comparison
    • Efficient updates
  2. Algorithm Steps:
    • Initialize counters
    • Process first window
    • Slide window
    • Compare frequencies

Implementation Details:

  • Frequency tracking
  • Window management
  • Comparison logic
  • Result collection

Optimization Insights:

  • Fixed-size arrays
  • Early validation
  • Efficient updates
  • Memory reuse

Edge Cases:

  • Empty strings
  • Single character
  • No anagrams
  • All anagrams