给你两个字符串 s1 和 s2 ,写一个函数来判断 s2 是否包含 s1 的排列。如果是,返回 true ;否则,返回 false 。
换句话说,s1 的排列之一是 s2 的 子串 。
示例 1:
输入:s1 = "ab" s2 = "eidbaooo"
输出:true
解释:s2 包含 s1 的排列之一 ("ba").
示例 2:
输入:s1= "ab" s2 = "eidboaoo"
输出:false
提示:
1 <= s1.length, s2.length <= 104
s1 和 s2 仅包含小写字母
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/permutation-in-string
思路:涉及到子串问题,我们考虑利用滑动窗口来解决。若s2包含s1的任意一个排列,则滑动窗口(在s2上滑动)的长度必定与s1相当,且窗口与s1中各个字符出现的次数相等。
具体过程是:先固定左指针left,我们遍历右指针right,不断扩大滑动窗口,对s1中存在的元素进行计数,当某个字符在s2中出现的次数==在s1中出现的次数,我们让winCount++。显然,当winCount的值与字符种类数count相等的时候,我们就应该开始缩小滑动窗口,当滑动窗口长度与s1长度相当的时候,返回true,否则返回false
class Solution {
public boolean checkInclusion(String s1, String s2) {
//s1字符数组和s2字符数组
char[] s1Char = s1.toCharArray();
char[] s2Char = s2.toCharArray();
//记录s1和s2中各个字符出现的次数
int[] s1CharCount = new int[26];
int[] s2CharCount = new int[26];
//s1的字符种类
int count = 0;
//记录s2中,字符出现次数与s1中该字符出现次数相等(或者大于)的字符的个数
int winCount = 0;
//滑动窗口的左右指针
int left = 0;
int right = 0;
//遍历s1Char,初始化s1CharCount,记录各个字符出现的次数
for(int i=0;i<s1Char.length;i++){
s1CharCount[s1Char[i]-'a']++;
}
//求得count
for(int i=0;i<s1CharCount.length;i++){
if(s1CharCount[i]>0){
count++;
}
}
//遍历s2数组(或者说是遍历s2字符串)
while(right<s2Char.length){
//获取right指向字符在数组中的下标
int dex = s2Char[right] - 'a';
//如果s2的该字符在s1中出现过,就在s2的计数数组中也进行技术
if(s1CharCount[dex]>0){
s2CharCount[dex]++;
if(s1CharCount[dex]==s2CharCount[dex]){
winCount++;
}
}
right++;
//满足此条件时,滑动窗口内的字符种类和数量均满足条件
while(winCount==count){
//长度相当,必定满足条件
if(right-left==s1.length()){
return true;
}
//长度不相当,缩小窗口,移动左指针
//获取left指向字符在数组中的下标
dex = s2Char[left] - 'a';
//如果left所指的s2的字符在s1中存在
if(s1CharCount[dex]>0){
//在s2中剔除一次该字符
s2CharCount[dex]--;
if(s2CharCount[dex]<s1CharCount[dex]){
winCount--;
}
}
left++;
}
}
return false;
}
}