给定两个字符串 s1
和 s2
,写一个函数来判断 s2
是否包含 s1
的排列。
换句话说,第一个字符串的排列之一是第二个字符串的子串。
示例1:
输入: s1 = "ab" s2 = "eidbaooo"
输出: True
解释: s2 包含 s1 的排列之一 ("ba").
示例2:
输入: s1= "ab" s2 = "eidboaoo"
输出: False
注意:
- 输入的字符串只包含小写字母
- 两个字符串的长度都在
[1, 10,000]
之间
解答
滑动窗口遍历,通过记录字符串每个字母出现次数来判断是否是排列。
class Solution {
public:
bool checkInclusion(string s1, string s2) {
if(s1.size() > s2.size())
return false;
vector<int> target(26, 0);
for(auto& c : s1){
target[c - 'a']++;
}
int left = 0;
for(int right = 0; right < s2.size(); right++){
if(right - left + 1 < s1.size())
continue;
string subs = s2.substr(left, right - left + 1);
if(isPermutation(subs, target)){
return true;
}
else{
left++;
}
}
return false;
}
bool isPermutation(string s, vector<int>& target){
vector<int> temp(26, 0);
for(auto& c : s){
temp[c - 'a']++;
}
for(int i = 0; i < 26; i++){
if(temp[i] != target[i])
return false;
}
return true;
}
};
实际上滑动窗口的大小是固定的,并且可以直接判断两个vector
是否相等:
class Solution {
public:
bool checkInclusion(string s1, string s2) {
if(s1.size() > s2.size())
return false;
// 还可以进一步优化,只使用一个vector来记录下列两个的差值。
vector<int> cnt1(26, 0);
vector<int> cnt2(26, 0);
for(int i = 0; i < s1.size(); i++){
cnt1[s1[i] - 'a']++;
cnt2[s2[i] - 'a']++;
}
if(cnt1 == cnt2)
return true;
for(int i = s1.size(); i < s2.size(); i++){
cnt2[s2[i] - 'a']++;
cnt2[s2[i - s1.size()] - 'a']--;
if(cnt1 == cnt2)
return true;
}
return false;
}
};