一、题目
给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。
换句话说,s1 的排列之一是 s2 的子串

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/permutation-in-string/description/
二、C++解法
我的思路及代码
滑动窗口
采用 left 和 right 来维护窗口当前的大小,两个 map 为 need 和 win 分别维护当前字串中所含有的各个字符的个数和当前窗口中含有目标字符的个数,valid 来维护当前窗口内满足需求的字符个数。总体思路为,先初始化窗口内的目标字符数量,然后同步扩大 left 和 right ,当 valid = need 的大小时,就说明此时的子串已经满足了需求,返回 true 即可,当 while 结束后说明不能满足条件,返回 false 。
class Solution {
public:
bool checkInclusion(string s1, string s2) {
if(s1.size()>s2.size()) return false;
int left,right,valid;
left = valid = 0;
right = s1.size();//维护一个大小为s1.size的窗口
unordered_map<char,int> need,win;
//初始化need表中的有效元素
for(int i=0;i<s1.size();i++)
need[s1[i]]++;
//初始化窗口中的有效元素
for(int i=0;i<s1.size();i++){
if(need.count(s2[i])){
win[s2[i]]++;
if(need[s2[i]] == win[s2[i]])
valid++;
}
}
//右指针越界的时候遍历结束
while(right<s2.size()){
//判断是否满足返回条件,放在前面是因为初始化valid和need后还木有进行判断,所以开始判断一次
if(valid == need.size())
return true;
char c = s2[left];
left++;
if(need.count(c)){
if(need[c] == win[c])
valid--;
win[c]--;
}
c = s2[right];
right++;
if(need.count(c)){
win[c]++;
if(need[c] == win[c])
valid++;
}
}
//结尾的时候right越界,但是还没有进行最后的判断,所以在返回时一并处理
return valid == need.size()?true:false;
}
};
- 时间复杂度:O(n+m+∣Σ∣),其中 n 是字符串 s1的长度,m 是字符串 s2的长度,Σ 是字符集,这道题中的字符集是小写字母,∣Σ∣=26
- 空间复杂度:空间复杂度:O(∣Σ∣)
官方参考代码
双指针

class Solution {
public:
bool checkInclusion(string s1, string s2) {
int n = s1.length(), m = s2.length();
if (n > m) {
return false;
}
vector<int> cnt(26);
for (int i = 0; i < n; ++i) {
--cnt[s1[i] - 'a'];
}
int left = 0;
for (int right = 0; right < m; ++right) {
int x = s2[right] - 'a';
++cnt[x];
while (cnt[x] > 0) {
--cnt[s2[left] - 'a'];
++left;
}
if (right - left + 1 == n) {
return true;
}
}
return false;
}
};
- 时间复杂度:O(n+m+∣Σ∣),其中 n 是字符串 s1的长度,m 是字符串 s2的长度,Σ 是字符集,这道题中的字符集是小写字母,∣Σ∣=26
- 空间复杂度:空间复杂度:O(∣Σ∣)
文章介绍了LeetCode上的一道题目,要求判断字符串s2是否包含s1的排列。提供了两种C++解法,一种使用滑动窗口,另一种使用双指针,分别详细解释了代码逻辑,并分析了时间复杂度和空间复杂度。
325

被折叠的 条评论
为什么被折叠?



