题目描述:
给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。
换句话说,第一个字符串的排列之一是第二个字符串的子串。
示例1:
输入: s1 = “ab” s2 = “eidbaooo”
输出: True
解释: s2 包含 s1 的排列之一 (“ba”).
示例2:
输入: s1= “ab” s2 = “eidboaoo”
输出: False
注意:
输入的字符串只包含小写字母
两个字符串的长度都在 [1, 10,000] 之间
方法1:滑动窗口
主要思路:
(1)和76题的最小覆盖子串类似,只不过需要获得的结果变化了,不再是要最小子串,而是要连续的排列是否存在,则只需要把判断条件从right-left<len来更新子字符串的大小和位置,变为right-left==s1.size()满足条件时,直接返回即可;
(2)考虑到题意中说的字符串中只有小写字母,故直接使用128大小的数组来映射字符,代替unordered_map;
class Solution {
public:
bool checkInclusion(string s1, string s2) {
//映射字符的数组
int need[128]={0};
int win[128]={0};
//统计s1中不重复的字符的数量
int size_s1_single=0;
//将s1中的字符进行映射
for(char ch:s1){
if(!need[ch])
size_s1_single++;
need[ch]++;
}
//滑动窗口的辅助变量
int left=0;
int right=0;
int valid=0;
//右侧窗口边界作为终止条件
while(right<s2.size()){
//扩展右侧窗口边界
char ch=s2[right++];
//判断当前字符是否是s1中的字符
if(need[ch]){
//若是,则同步更新窗口win
win[ch]++;
//统计当前窗口内满足要求的字符的数量
if(win[ch]==need[ch])
++valid;
}
//若当前窗口内含有s1的全部字符
while(valid==size_s1_single){
//若当前窗口的长度和s1的长度一致,即为一个全排列,则直接返回结果
if(right-left==s1.size())
return true;
//更新左侧窗口
ch=s2[left++];
if(need[ch]){
if(need[ch]==win[ch])
--valid;
win[ch]--;
}
}
}
//若跳出,则说明没有找到满足要求的字符串,则直接返回
return false;
}
};