🎨Now live: Try our Free AI Image Generation Feature
Description
Given two strings s1
and s2
, your goal is to determine if one string's permutation is a substring of the other. Specifically, check whether any permutation of s1
exists within s2
. If so, return true
, otherwise return false
.
Intuition
The problem requires checking for a permutation of one string (s1
) within the other (s2
). A permutation involves rearranging characters, but since it’s only rearranging, the count of each character must match between the two strings. Thus, the task boils down to comparing character frequencies in sliding windows of s2
that match the length of s1
.
Approach
- Initial Setup:
- Create two frequency arrays (or maps) to store character counts for
s1
and the first window ins2
of length equal tos1
. - Sliding Window Technique:
- Use a sliding window over
s2
, moving from the start to the end, adjusting the character frequencies dynamically for each window. - Compare the character counts of the current window ins2
with the character counts ofs1
. If they match, returntrue
. - Edge Case:
- If
s1
is longer thans2
, directly returnfalse
because it is impossible for a longer string to be a permutation of a shorter one.
Complexity
- Time Complexity: O(n), where
n
is the length ofs2
. Both strings1
ands2
are iterated once. Checking for matching frequencies is constant time since there are only 26 possible characters (for lowercase English letters). - Space Complexity: O(1), because the frequency array or map has a fixed size of 26 for lowercase characters, regardless of input size.
Code
C++
class Solution {
public:
bool checkInclusion(string s1, string s2) {
if (s1.size() > s2.size()) return false;
vector cache1(26, 0), cache2(26, 0);
for (int i = 0; i < s1.size(); ++i) {
cache1[s1[i] - 'a']++;
cache2[s2[i] - 'a']++;
}
auto checkCache = [&]() {
return cache1 == cache2;
};
if (checkCache()) return true;
for (int i = s1.size(); i < s2.size(); ++i) {
cache2[s2[i - s1.size()] - 'a']--;
cache2[s2[i] - 'a']++;
if (checkCache()) return true;
}
return false;
}
};
Python
class Solution:
def checkInclusion(self, s1: str, s2: str) -> bool:
if len(s1) > len(s2):
return False
cache1 = [0] * 26
cache2 = [0] * 26
for i in range(len(s1)):
cache1[ord(s1[i]) - ord('a')] += 1
cache2[ord(s2[i]) - ord('a')] += 1
if cache1 == cache2:
return True
for i in range(len(s1), len(s2)):
cache2[ord(s2[i - len(s1)]) - ord('a')] -= 1
cache2[ord(s2[i]) - ord('a')] += 1
if cache1 == cache2:
return True
return False
Java
class Solution {
public boolean checkInclusion(String s1, String s2) {
if (s1.length() > s2.length()) return false;
int[] cache1 = new int[26], cache2 = new int[26];
for (int i = 0; i < s1.length(); ++i) {
cache1[s1.charAt(i) - 'a']++;
cache2[s2.charAt(i) - 'a']++;
}
if (Arrays.equals(cache1, cache2)) return true;
for (int i = s1.length(); i < s2.length(); ++i) {
cache2[s2.charAt(i - s1.length()) - 'a']--;
cache2[s2.charAt(i) - 'a']++;
if (Arrays.equals(cache1, cache2)) return true;
}
return false;
}
}
JavaScript
var checkInclusion = function (s1, s2) {
if (s1.length > s2.length) return false;
const cache1 = {};
const cache2 = {};
for (let i = 0; i < s1.length; i++) {
s1[i] in cache1 ? cache1[s1[i]]++ : cache1[s1[i]] = 1;
s2[i] in cache2 ? cache2[s2[i]]++ : cache2[s2[i]] = 1;
}
const checkCache = (cache1, cache2) => {
if (Object.values(cache1).length !== Object.values(cache2).length) return false;
for (const key in cache1) {
if (cache1[key] !== cache2[key]) {
return false;
}
}
return true;
}
if (checkCache(cache1, cache2)) return true;
for (let i = s1.length; i < s2.length; i++) {
let charOut = s2[i - s1.length];
cache2[charOut] === 1 ? delete cache2[charOut] : cache2[charOut]--;
let charIn = s2[i];
cache2[charIn] ? cache2[charIn]++ : cache2[charIn] = 1;
if (checkCache(cache1, cache2)) return true;
}
return false;
};