
Description
The problem requires finding all starting indices of substring(s) in a given string s
that is an anagram of a given string p
. An anagram of a string is another string that contains the same characters, only the order of the characters can be different.
Intuition
To solve this problem, we need to compare substrings of s
with the string p
. A substring is an anagram of p
if the character frequencies in the substring match the frequencies in p
. Therefore, the problem reduces to comparing character frequency counts.
Approach
- Initialization:
- Compute the frequency of each character in
p
and store it in a listpmap
. - Initialize a listsmap
to keep track of the frequency of characters in the current window of size equal top
ins
. - First Window:
- Populate
smap
with the frequencies of characters in the first window of lengthp
froms
. - Sliding Window:
- Compare
smap
withpmap
. If they are equal, add the starting index of the window to the result list. - Slide the window one character at a time to the right by updatingsmap
: - Add the frequency of the new character coming into the window. - Subtract the frequency of the character leaving the window. - Final Check:
- After the loop, ensure that the last window (if not already checked) is compared with
pmap
. - Return Results: - Return the list of starting indices where anagrams are found.
Complexity
Time Complexity:
O(n), where n
is the length of the string s
. The algorithm processes each character in s
once, and the frequency comparison is done in constant time since the frequency arrays have a fixed size (26 for lowercase English letters).
Space Complexity:
O(1). The space used for storing frequency counts is constant (26 elements for each frequency array), and the result list's size depends on the number of valid anagrams found.
Code
C++
class Solution {
public:
vector findAnagrams(string s, string p) {
vector result;
if (s.length() < p.length()) {
return result;
}
vector pmap(26, 0);
vector smap(26, 0);
for (char c : p) {
pmap[c - 'a']++;
}
for (int i = 0; i < p.length(); i++) {
smap[s[i] - 'a']++;
}
if (smap == pmap) {
result.push_back(0);
}
for (int i = p.length(); i < s.length(); i++) {
smap[s[i] - 'a']++;
smap[s[i - p.length()] - 'a']--;
if (smap == pmap) {
result.push_back(i - p.length() + 1);
}
}
return result;
}
};
Python
class Solution:
def findAnagrams(self, s: str, p: str) -> List[int]:
if len(s) < len(p):
return []
pmap = [0] * 26
smap = [0] * 26
result = []
for char in p:
pmap[ord(char) - ord('a')] += 1
for i in range(len(p)):
smap[ord(s[i]) - ord('a')] += 1
if smap == pmap:
result.append(0)
for i in range(len(p), len(s)):
smap[ord(s[i]) - ord('a')] += 1
smap[ord(s[i - len(p)]) - ord('a')] -= 1
if smap == pmap:
result.append(i - len(p) + 1)
return result
Java
class Solution {
public List findAnagrams(String s, String p) {
List result = new ArrayList<>();
if (s.length() < p.length()) {
return result;
}
int[] pmap = new int[26];
int[] smap = new int[26];
for (char c : p.toCharArray()) {
pmap[c - 'a']++;
}
for (int i = 0; i < p.length(); i++) {
smap[s.charAt(i) - 'a']++;
}
if (matches(smap, pmap)) {
result.add(0);
}
for (int i = p.length(); i < s.length(); i++) {
smap[s.charAt(i) - 'a']++;
smap[s.charAt(i - p.length()) - 'a']--;
if (matches(smap, pmap)) {
result.add(i - p.length() + 1);
}
}
return result;
}
private boolean matches(int[] smap, int[] pmap) {
for (int i = 0; i < smap.length; i++) {
if (smap[i] != pmap[i]) {
return false;
}
}
return true;
}
}
JavaScript
/**
* @param {string} s
* @param {string} p
* @return {number[]}
*/
var findAnagrams = function(s, p) {
if (s.length < p.length) {
return []
}
const pmap = new Array(26).fill(0);
for (let i = 0; i < p.length; i++) {
pmap[p.charAt(i).charCodeAt(0) - 97]++;
}
const result = [];
const smap = new Array(26).fill(0);
for (let i = 0; i {
for (let i = 0; i < arr1.length; i++) {
if (arr1[i] != arr2[i]) {
return false;
}
}
return true;
}