《LeetCode之每日一题》:87.字符串的排列
Posted 是七喜呀!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《LeetCode之每日一题》:87.字符串的排列相关的知识,希望对你有一定的参考价值。
题目链接: 字符串的排列
有关题目
给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。
换句话说,第一个字符串的排列之一是第二个字符串的 子串 。
示例 1:
输入: s1 = "ab" s2 = "eidbaooo"
输出: True
解释: s2 包含 s1 的排列之一 ("ba").
示例 2:
输入: s1= "ab" s2 = "eidboaoo"
输出: False
提示:
输入的字符串只包含小写字母
两个字符串的长度都在 [1, 10,000] 之间
题解
法一:滑动窗口
思路:
子串必须长度相同,我们维护长度为s2。length的在s1中的子串,
使用滑动窗口,判断是否存在子串间排列关系
bool equals(int* cnt1, int* cnt2) {
for (int i = 0; i < 26; i++) {
if (cnt1[i] != cnt2[i]) {
return false;
}
}
return true;
}
bool checkInclusion(char * s1, char * s2){
int n = strlen(s1), m = strlen(s2);
if (n > m) {
return false;
}//特判
int cnt1[26], cnt2[26];
memset(cnt1,0,sizeof(cnt1));
memset(cnt2,0,sizeof(cnt2));
for (int i = 0; i < n ; ++i){
++cnt1[s1[i] - 'a'];
++cnt2[s2[i] - 'a'];
}
if (equals(cnt1, cnt2)) {
return true;
}
for (int i = n; i < m; ++i){
++cnt2[s2[i] - 'a'];//窗口滑动
--cnt2[s2[i - n] - 'a'];//少统计一个出窗口的字符
if (equals(cnt1, cnt2)) {
return true;
}
}
return false;
}
法二:滑动窗口优化
思路:
注意到每次窗口滑动时,只统计了一进一出两个字符,却比较了整个cnt1 与cnt2 数组
我们使用diff来记录cnt1 与 cnt2的不同值的个数,若
diff==0,则满足题意
每次窗口滑动,记一进一出两个字符为x 和 y,讨论x与y之间的相等关系
此外,为简化上述逻辑,我们可以只用一个数组
cnt[x] = cnt2[x] - cnt1[x]
将cnt1[x] 与cnt2[x]之间的大小关系转换为cnt[x]与0之间的比较
bool checkInclusion(char * s1, char * s2){
int n = strlen(s1), m = strlen(s2);
if (n > m) {
return false;
}
int cnt[26];
memset(cnt, 0, sizeof(cnt));
for (int i = 0; i < n; ++i) {
--cnt[s1[i] - 'a'];
++cnt[s2[i] - 'a'];
}
int diff = 0;
for (int i = 0; i < 26; ++i) {
if (cnt[i] != 0) {
++diff;
}
}
if (diff == 0) {
return true;
}
for (int i = n; i < m; ++i) {
int x = s2[i] - 'a', y = s2[i - n] - 'a';
if (x == y) {
continue;
}
if (cnt[x] == 0) {//x进之前,满足字符相同
++diff;//不同字符+1
}
++cnt[x];
if (cnt[x] == 0) {//x进之后,满足字符相同
--diff;//不同字符-1
}
if (cnt[y] == 0) {//y出,相类似
++diff;
}
--cnt[y];
if (cnt[y] == 0) {
--diff;
}
if (diff == 0) {
return true;
}
}
return false;
}
法三:双指针
思路:
法一与二控制窗口长度为n,看是否满足区间使得cnt值全为0
双指针,反过来,保证cnt不为正的情况下,考察一个区间是否
长度为n
//①:cnt[x] = cnt2[x] - cnt1[x] 为正,则
说明这个字符,s1并没有那么多,要窗口左移,不然肯定不会有cnt为正的时机,剔除left上的s2字符
//②:如果不大于,说明start字符在s2的出现次数还没达到s1的标准,窗口要扩张。纳入新字符
如果遍历s2结束,始终没有返回真,说明怎么也找不到,返回假
bool checkInclusion(char * s1, char * s2){
int n = strlen(s1), m = strlen(s2);
if (n > m) {
return false;
}
int cnt[26];
memset(cnt, 0, sizeof(cnt));
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;
}
以上是关于《LeetCode之每日一题》:87.字符串的排列的主要内容,如果未能解决你的问题,请参考以下文章
《LeetCode之每日一题》:94.面试题 10.02. 变位词组