其他分享
首页 > 其他分享> > 567. 字符串的排列(中等,双指针,滑动窗口)

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