Problem Statement
Given two strings s and p, return all start indices of p’s anagrams in s. You may return the answer in any order.
An anagram is a rearrangement of letters. For example, "abc" and "cab" are anagrams.
Example 1:
Input: s = "cbaebabacd", p = "abc"
Output: [0, 6]
Explanation:
- Substring
"cba"at index 0 is an anagram of"abc". - Substring
"bac"at index 6 is an anagram of"abc".
Example 2:
Input: s = "abab", p = "ab"
Output: [0, 1, 2]
Constraints:
- 1 <= s.length, p.length <= 3 * 10^4
sandpconsist of lowercase English letters.
Approach in Plain English
- Since we are looking for all anagrams of
pins, the length of substring we care about is alwaysp.length. - Use sliding window technique:
- Maintain a window of size
p.lengthwhile iterating throughs. - Track frequency of characters in
pand the current window ofs.
- Maintain a window of size
- For each window:
- If frequency counts match exactly, it’s an anagram → add starting index to result.
- Use an array of size 26 to store character counts (faster than HashMap).
- Slide the window:
- Add new character (right end), remove old character (left end) from window counts.
- Compare updated counts with
p’s counts.
Key idea: Sliding window reduces the problem from O(n * m) (checking every substring) to O(n), where n = s.length.
Dry Run Example
Take s = "cbaebabacd", p = "abc".
p.length = 3, so window size = 3.- Count frequencies in
p:a=1, b=1, c=1. - Slide the window through
s:- Window
"cba"(indices 0-2):- Count:
c=1, b=1, a=1→ matchesp→ add 0 to result.
- Count:
- Window
"bae"(indices 1-3):- Count:
b=1, a=1, e=1→ doesn’t match → skip.
- Count:
- Window
"aeb"(indices 2-4):- Count:
a=1, e=1, b=1→ doesn’t match → skip.
- Count:
- Window
"bac"(indices 6-8):- Count:
b=1, a=1, c=1→ matchesp→ add 6 to result.
- Count:
- Window
- Result →
[0, 6].
Textual Approach
- Prepare frequency count for
p. - Use two pointers for sliding window:
startandend. - Maintain count array for current window.
- If window size equals
p.length:- Compare counts → if same, add
startto result. - Slide the window by moving
startforward.
- Compare counts → if same, add
- Repeat until
endreaches end ofs.
Java Code
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;
public class FindAllAnagrams {
public static List<Integer> findAnagrams(String s, String p) {
List<Integer> res = new ArrayList<>();
if (s.length() < p.length()) return res;
int[] pCount = new int[26];
int[] windowCount = new int[26];
// Count frequency of characters in p
for (char c : p.toCharArray()) {
pCount++;
}
int windowSize = p.length();
for (int i = 0; i < s.length(); i++) {
// Add current character to window
windowCount[s.charAt(i) - 'a']++;
// Remove leftmost character if window exceeded size
if (i >= windowSize) {
windowCount[s.charAt(i - windowSize) - 'a']--;
}
// Compare arrays for match
if (Arrays.equals(pCount, windowCount)) {
res.add(i - windowSize + 1);
}
}
return res;
}
public static void main(String[] args) {
String s = "cbaebabacd";
String p = "abc";
List<Integer> result = findAnagrams(s, p);
System.out.println(result); // Output: [0, 6]
}
}
Key Points
- Sliding window reduces time complexity from O(n * m) to O(n)
(n = length ofs, m = length ofp). - Use frequency arrays of size 26 for lowercase letters.
- Always remove the leftmost character when the window size exceeds
p.length. - Compare arrays efficiently using
Arrays.equals.
