🧠
Brute Force (Check All Substrings)
💡 This approach exists to build intuition by directly checking every possible substring of length p and verifying if it is an anagram. It is simple but inefficient, highlighting why optimization is needed.
Intuition
Check every substring of s with length equal to p, and for each substring, check if it contains the same characters with the same frequency as p.
Algorithm
- Iterate over all substrings of s with length equal to p.
- For each substring, count the frequency of characters.
- Compare the frequency map of the substring with that of p.
- If they match, record the start index.
💡 The main difficulty is realizing that checking every substring independently leads to repeated work and inefficiency.
from collections import Counter
def findAnagrams(s: str, p: str) -> list:
res = []
p_len = len(p)
p_count = Counter(p)
for i in range(len(s) - p_len + 1):
window = s[i:i+p_len]
window_count = Counter(window)
if window_count == p_count:
res.append(i)
return res
# Example usage
if __name__ == '__main__':
print(findAnagrams("cbaebabacd", "abc")) # Output: [0, 6]
Line Notes
from collections import CounterImport Counter to easily count character frequencies
p_count = Counter(p)Precompute frequency of characters in p once
for i in range(len(s) - p_len + 1)Iterate over all possible substrings of length p_len
window_count = Counter(window)Count characters in current substring from scratch
if window_count == p_countCheck if current substring is an anagram by comparing counts
res.append(i)Record starting index if an anagram is found
import java.util.*;
public class Solution {
public List<Integer> findAnagrams(String s, String p) {
List<Integer> res = new ArrayList<>();
int pLen = p.length();
Map<Character, Integer> pCount = new HashMap<>();
for (char c : p.toCharArray()) {
pCount.put(c, pCount.getOrDefault(c, 0) + 1);
}
for (int i = 0; i <= s.length() - pLen; i++) {
String window = s.substring(i, i + pLen);
Map<Character, Integer> windowCount = new HashMap<>();
for (char c : window.toCharArray()) {
windowCount.put(c, windowCount.getOrDefault(c, 0) + 1);
}
if (windowCount.equals(pCount)) {
res.add(i);
}
}
return res;
}
public static void main(String[] args) {
Solution sol = new Solution();
System.out.println(sol.findAnagrams("cbaebabacd", "abc")); // Output: [0, 6]
}
}
Line Notes
Map<Character, Integer> pCount = new HashMap<>()Create frequency map for p
for (int i = 0; i <= s.length() - pLen; i++)Loop over all substrings of length pLen
Map<Character, Integer> windowCount = new HashMap<>()Create frequency map for current substring
if (windowCount.equals(pCount))Check if current substring is an anagram
res.add(i)Add starting index to result list
#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
using namespace std;
vector<int> findAnagrams(string s, string p) {
vector<int> res;
int pLen = p.size();
unordered_map<char, int> pCount;
for (char c : p) {
pCount[c]++;
}
for (int i = 0; i <= (int)s.size() - pLen; i++) {
unordered_map<char, int> windowCount;
for (int j = i; j < i + pLen; j++) {
windowCount[s[j]]++;
}
if (windowCount == pCount) {
res.push_back(i);
}
}
return res;
}
int main() {
vector<int> result = findAnagrams("cbaebabacd", "abc");
for (int idx : result) cout << idx << " ";
cout << endl; // Output: 0 6
return 0;
}
Line Notes
unordered_map<char, int> pCount;Frequency map for p
for (int i = 0; i <= (int)s.size() - pLen; i++)Iterate over all substrings of length pLen
unordered_map<char, int> windowCount;Frequency map for current substring
if (windowCount == pCount)Compare frequency maps to check anagram
res.push_back(i);Store starting index if anagram found
function findAnagrams(s, p) {
const res = [];
const pLen = p.length;
const pCount = new Map();
for (const c of p) {
pCount.set(c, (pCount.get(c) || 0) + 1);
}
for (let i = 0; i <= s.length - pLen; i++) {
const window = s.substring(i, i + pLen);
const windowCount = new Map();
for (const c of window) {
windowCount.set(c, (windowCount.get(c) || 0) + 1);
}
if (mapsEqual(pCount, windowCount)) {
res.push(i);
}
}
return res;
}
function mapsEqual(m1, m2) {
if (m1.size !== m2.size) return false;
for (const [key, val] of m1) {
if (m2.get(key) !== val) return false;
}
return true;
}
// Example usage
console.log(findAnagrams("cbaebabacd", "abc")); // Output: [0, 6]
Line Notes
const pCount = new Map();Create frequency map for p
for (let i = 0; i <= s.length - pLen; i++)Loop over all substrings of length pLen
const windowCount = new Map();Frequency map for current substring
if (mapsEqual(pCount, windowCount))Check if current substring is an anagram
res.push(i);Add starting index to result array
TimeO((n - m + 1) * m) where n = len(s), m = len(p)
SpaceO(m) for frequency maps
For each of the n-m+1 substrings, we count frequencies in O(m) time, leading to O(n*m) total.
💡 If s and p are length 20, this means about 400 operations, but for 100,000 length strings this becomes 10 billion operations, which is too slow.
Interview Verdict: TLE / Use only to introduce
This approach is too slow for large inputs but is useful to understand the problem and motivate optimizations.