Leetcode 438. Find All Anagrams in a String
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.
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".
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".
1 <= s.length, p.length <= 3 * 10^4
s
and p
consist of lowercase English letters.s
and p
be empty?
s
and p
will have at least one character.s
or p
?
s
be smaller than p
?
s
and p
both have lengths between 1 and 30000, and it’s implicitly given that we will only perform operations when looking for anagrams where it makes sense (i.e., s.length
should be greater or equal top.length
).To find all anagrams of the string p
in s
, we’ll leverage a sliding window technique with a frequency counter. The idea is to maintain a window of length equal to p
and slide it across s
, updating the frequency counts of characters and checking if they match the character frequency of p
.
p
and the current window in s
.p
from the start of s
.import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class AnagramFinder {
public List<Integer> findAnagrams(String s, String p) {
List<Integer> result = new ArrayList<>();
if(s.length() < p.length()) return result;
int[] pCount = new int[26];
int[] sCount = new int[26];
// Count frequency of each character in p
for(char ch : p.toCharArray()) {
pCount[ch - 'a']++;
}
// Populate the initial window
for(int i = 0; i < p.length(); i++) {
sCount[s.charAt(i) - 'a']++;
}
// Check if initial window matches
if(Arrays.equals(sCount, pCount)) {
result.add(0);
}
// Slide the window across `s`
for(int i = p.length(); i < s.length(); i++) {
// add new character to the window
sCount[s.charAt(i) - 'a']++;
// remove the old character from the window
sCount[s.charAt(i - p.length()) - 'a']--;
// check if matching
if(Arrays.equals(sCount, pCount)) {
result.add(i - p.length() + 1);
}
}
return result;
}
}
O(p.length)
O((s.length - p.length + 1) * 26)
, since in the worst case we compare two frequency arrays of size 26 for each window.O(s.length * 26)
, which simplifies to O(26 * s.length)
. Since 26 is a constant (O(1)
), the final complexity is essentially O(s.length)
.This approach efficiently finds all starting indices of anagrams of p
in s
by using sliding window and constant-time character frequency comparison.
Got blindsided by a question you didn’t expect?
Spend too much time studying?
Or simply don’t have the time to go over all 3000 questions?