Given two strings s1 and s2, write a function to return true if s2 contains the permutation of s1. In other words, one of the first string's permutations is the substring of the second string.
Example 1:
Input:s1 = "ab" s2 = "eidbaooo"
Output:True
Explanation: s2 contains one permutation of s1 ("ba").
Example 2:
Input:s1= "ab" s2 = "eidboaoo" Output: False
Note:
- The input strings only contain lower case letters.
- The length of both given strings is in range [1, 10,000].
Related Topics:
Two Pointers
Similar Questions:
Store the counts of letters of s1 in cnts array.
- When we consume a letter
s2[i], we decrement its count. - When we pop a letter
s2[i - N], we increment its count. We start popping wheni - N >= 0to make sure the sliding window is at most as long ass1.
Once all the counts in cnts array are zeros, we return true. If we reached end of array and still haven't clear out the cnts, return false.
The time complexity is O(26 * S2) = O(S2).
// OJ: https://leetcode.com/problems/permutation-in-string/
// Author: github.com/lzl124631x
// Time: O(S2)
// Space: O(1)
class Solution {
public:
bool checkInclusion(string s1, string s2) {
if (s1.size() > s2.size()) return false;
int N = s1.size();
int cnts[26] = {0};
for (char c : s1) cnts[c - 'a']++;
for (int i = 0; i < s2.size(); ++i) {
cnts[s2[i] - 'a']--;
if (i - N >= 0) cnts[s2[i - N] - 'a']++;
bool match = true;
for (int j = 0; j < 26 && match; ++j) {
if (cnts[j]) match = false;
}
if (match) return true;
}
return false;
}
};Similar to Solution 1, we keep a sliding window of size s1.size(). Instead of checking the count for 26 characters, we just use a count variable to store the number of matched characters within the sliding window.
// OJ: https://leetcode.com/problems/permutation-in-string/
// Author: github.com/lzl124631x
// Time: O(S2)
// Space: O(1)
class Solution {
public:
bool checkInclusion(string s1, string s2) {
if (s1.size() > s2.size()) return false;
int cnt[26] = {}, count = s1.size(), N = s1.size();
for (char c : s1) cnt[c - 'a']++;
for (int i = 0; i < s2.size(); ++i) {
if (i >= N) count += cnt[s2[i - N] - 'a']++ >= 0;
count -= cnt[s2[i] - 'a']-- > 0;
if (!count) return true;
}
return false;
}
};We keep the counts of letters of s1 in goal array. And we use two pointers i and j to consume s2, and store the counts of letters within range [i, j) in cnt array.
- We keep incrementing
jand the corresponding countcnt[s2[j]]until it reaches the end orcnt[s2[j]] + 1 <= goal[s2[j]]. LetXbes2[j]thenXis the letter we don't want to consume. - If the gap between
iandjis the length ofs1, then we've found match and just returntrue. - Since
s2[j]is unwanted, we keep poppings2[i]by incrementingiuntils2[i] == s2[j], meanwhile, we decrementcnt[s2[i]]. - Now
s[i]ands[j]are all pointing to the unwanted letterX, incrementiandjboth so that thecnt[X]will be unchanged. Go to Step 1 untiljreaches end.
// OJ: https://leetcode.com/problems/permutation-in-string/
// Author: github.com/lzl124631x
// Time: O(S2)
// Space: O(1)
class Solution {
public:
bool checkInclusion(string s1, string s2) {
int M = s1.size(), N = s2.size(), i = 0, j = 0, goal[26] = {0}, cnt[26] = {0};
for (char c : s1) goal[c - 'a']++;
for (; j < N; ++i, ++j) {
while (j < N && cnt[s2[j] - 'a'] + 1 <= goal[s2[j] - 'a']) cnt[s2[j++] - 'a']++;
if (j - i == M) return true;
while (j < N && i < j && s2[i] != s2[j]) cnt[s2[i++] - 'a']--;
}
return false;
}
};