Check if a string contains an anagram of another string
Problem
Given two strings s1 and s2, determine if s1 contains any substring that is an anagram of s2.
An anagram is a rearrangement of all the letters of a string.
Return true if such a substring exists, otherwise return false.
Examples
Example 1
Input: s1 = "coding interview questions", s2 = "weivretni"
Output: true
Explanation: "interview" is a substring of s1 and is an anagram of s2.
Example 2
Input: s1 = "coding interview questions", s2 = "abcde"
Output: false
Explanation: No substring of s1 is an anagram of s2.
Solution
We have a similar problem - [Find anagrams of a string in another string](find-anagrams-of-a-string-in-another-string). But there we have find the anagram, here we have to just check.
In case you don’t know what anagram is – check it out here - [Anagram Definition](/gk/algorithms/anagram-definition).
Method 1 - Using Sliding window
Solution
Method 1 - Brute force
A basic brute force method is to generate all possible substrings of s1 with the same length as s2 and check each one for being an anagram.
One way to verify an anagram is by computing a hash for each string, such as assigning a unique prime number to each character and multiplying these primes for the hash; this allows linear-time comparison.
However, since there are O(N^2) substrings and each check takes O(M), the overall time complexity is O(N^2 * M), which is inefficient and generally not recommended.
Method 2 - Sliding window
- An anagram of
s2must have the same character counts ass2. - We can use a sliding window of length equal to
s2overs1and compare character counts. - If any window matches, return
true.
Approach
- If
len(s2) > len(s1), returnfalse. - Count the frequency of each character in
s2. - Use a sliding window of size
len(s2)overs1:- Maintain a count of characters in the current window.
- If the counts match at any point, return
true.
- If no window matches, return
false.
Code
Java
class Solution {
public boolean containsAnagram(String s1, String s2) {
if (s2.length() > s1.length()) return false;
int[] cntS2 = new int[256], cntW = new int[256];
for (char c : s2.toCharArray()) cntS2[c]++;
for (int i = 0; i < s2.length(); i++) cntW[s1.charAt(i)]++;
if (matches(cntS2, cntW)) return true;
for (int i = s2.length(); i < s1.length(); i++) {
cntW[s1.charAt(i)]++;
cntW[s1.charAt(i - s2.length())]--;
if (matches(cntS2, cntW)) return true;
}
return false;
}
private boolean matches(int[] a, int[] b) {
for (int i = 0; i < 256; i++) if (a[i] != b[i]) return false;
return true;
}
}
Python
class Solution:
def contains_anagram(self, s1: str, s2: str) -> bool:
if len(s2) > len(s1):
return False
from collections import Counter
cnt_s2: Dict[str, int] = Counter(s2)
cnt_w: Dict[str, int] = Counter(s1[:len(s2)])
if cnt_s2 == cnt_w:
return True
for i in range(len(s2), len(s1)):
cnt_w[s1[i]] += 1
cnt_w[s1[i - len(s2)]] -= 1
if cnt_w[s1[i - len(s2)]] == 0:
del cnt_w[s1[i - len(s2)]]
if cnt_s2 == cnt_w:
return True
return False
Complexity
- ⏰ Time complexity:
O(N)where N is the length of string s1. - 🧺 Space complexity:
O(1)(since the alphabet size is constant, e.g., 26 or 256).