567. 字符串的排列(中等,双指针,滑动窗口)
作者:互联网
题目链接:567. 字符串的排列
思路:我可以在s2上维持一个s1长度的窗口,并滑动,每次比较这个窗口内排序后是否为s1排序后相同
官方三种答案,我就想到了一种。。。。略有区别于官方答案
class Solution {
public:
//思路;在s2上 保持s1长度的滑动窗口; 自左向右移动 分别排序后 对比
//这里的桶也可以修改为哈希表
bool str_isornot_equal(string& s1, string& s2, int start, int end) {
int tong[26] = { 0 };
for (char s : s1) {
int i = s - 'a';
tong[i]++;
}
for (start; start <= end; start++) {
int i = s2[start] - 'a';
tong[i]--;
}
for (int x : tong) {
if (x != 0) {
return false;
}
}
return true;
}
bool checkInclusion(string s1, string s2) {
if (s1.size() > s2.size()) {
return false;
}
int n = s1.size(); //子串长度
int slow = 0;
int fast = n - 1;
for (fast; fast < s2.size(); fast++) { //这里有双for 时间复杂度高
if (str_isornot_equal(s1, s2, slow, fast)) {
return true;
}
slow++;
}
return false;
}
};
思路二:真正的滑动窗口,一进一出的滑动窗口,相当于在我的版本上改进
比我多了个容器
class Solution {
public:
bool checkInclusion(string s1, string s2) {
int n = s1.length(), m = s2.length();
if (n > m) {
return false;
}
vector<int> cnt1(26), cnt2(26); //桶, 比我多一个容器
for (int i = 0; i < n; ++i) {
++cnt1[s1[i] - 'a'];
++cnt2[s2[i] - 'a'];
}
if (cnt1 == cnt2) {
return true;
}
//与我的思路不同的在这里
for (int i = n; i < m; ++i) {
++cnt2[s2[i] - 'a']; //加一个减一个保持长度不变 实现滑动窗口
--cnt2[s2[i - n] - 'a'];
if (cnt1 == cnt2) {
return true;
}
}
return false;
}
};
思路三:在思路二上改进,我觉得改的很垃圾,全是if了
//上面一进一出 却要比较整个数组 所以可以优化
//在上面基础上优化 改的看都看不懂 这么多if 何必呢
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'];
++cnt[s2[i] - 'a'];
}
int diff = 0; //记录不同值的个数
for (int c : cnt) {
if (c != 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) { //进数了 如果刚开始为相同的 现在为不同的 所以+1
++diff;
}
++cnt[x];
if (cnt[x] == 0) { //如果刚开始为不同的 现在为相同的 所以-1
--diff;
}
if (cnt[y] == 0) {
++diff;
}
--cnt[y];
if (cnt[y] == 0) {
--diff;
}
if (diff == 0) {
return true;
}
}
return false;
}
};
思路四:双指针,懵懵懂懂
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;
}
};
可以看出来四种方法都是用桶装数据,同样道理也可以改为哈希表装数据
中等题我唯唯诺诺。。。
标签:cnt,return,int,s2,s1,567,++,滑动,指针 来源: https://blog.csdn.net/qq_39236499/article/details/121160405