【滑动窗口】判断s2是否包含s1的全排列

大致思路:

s2必须要包含s1的某种排列,必须是包含的那种连续的。

刚开始我用全排列输出各种s1的排列,在递归的临界条件那儿判断是否被s2包含。显然,就算剪枝仍然超时,想想确实也是,人家递归类似于dfs是用来输出详细的组合信息的,而这里好像没这个必要这样做。不过,这个代码仍然有值得学习的地方:①输出全排列的递归算法温习(当前字符不在之后的组合中,若在则需要遍历位置);②判断两个字符串的包含函数:string.find是否==string.npos。不要和之前的“判断vector中是否存在find”和“判断字符数组是否包含strstr”搞混。

#include<bits/stdc++.h>
class Solution {
public:
    bool flag = false;
    bool checkInclusion(string s1, string s2) {
        int len1=s1.size();
        int len2=s2.size();
        if(len1>len2)
            return false;
        if(len1==len2&&len1==0)
            return true;
        QuanPaiLie(s1,s2,0);
        if(flag)
            return true;
        else
            return false;
    }
    
    void QuanPaiLie(string &s,string s2,int begin)
    {
        if(flag==true) //剪枝
            return;
        
        if(begin==s.size()-1)
        {
            //判断是否被s2包含
            // if(find(s2.begin(),s2.end(),s)!=s2.end()) //find是用于在vector中找的!这里是字符串,不行
            // if( strstr(s2,s)!=NULL ) //字符串判断是否包含用str(母串,子串) 包含返回首地址,不包含则返回NULL。但是!!!前提是s2和s都是字符数组,而非字符串string类型
            //最后终于找到方法:string.find,没找到则返回string.npos
            if(s2.find(s)!=s2.npos)
            {
                flag=true;
                return;
            }
            else
                return;
        }
        for(int i=begin;i<s.size();i++)
        {
            swap(s,begin,i);
            QuanPaiLie(s,s2,begin+1);
            swap(s,begin,i);
        }
    }
    
    void swap(string &s,int i,int j)
    {
        int temp = s[i];
        s[i] = s[j];
        s[j] = temp;
    }
    
};

后来,结合题目分析,说是求全排列是否对应上,其实就看那一块儿是不是各个字母出现的次数都一样。(不管怎么排列,各字母出现的次数是不变的)

于是(理解之后才觉得简单):

① 用两个vector来存储每个字母在s1或s2中在滑动窗口内出现的次数,如果v1==v2则说明这个滑动窗口就是所求,返回true。注意要用vector,才能直接通过==来比较相等。

② 移动“滑动窗口”,头字符的出现次数-1,下一个新字符的出现次数+1,如此保证滑动窗口大小不变地向后平移。每次平移都要判断一次v1==v2.

class Solution {
public:
    bool checkInclusion(string s1, string s2) {
        vector<int> v1(26,0); //记录s1各个单词出现的次数
        vector<int> v2(26,0); 
        int len1 = s1.size();
        int len2 = s2.size();
        if(len1>len2)
            return false;
        if(len1==len2&&len1==0)
            return true;
        
        for(int i=0;i<len1;i++) //先来看第一个滑动窗口
        {
            v1[s1[i]-'a']++;
            v2[s2[i]-'a']++;
        }
        if(v1==v2)
            return true; //表示s2的前len1个即s1的一种排列
        
        for(int i=0;i+len1<len2;i++) //长度为len1的滑动窗口开始向后平移
        {
            v2[s2[i]-'a']--; //后移头
            v2[s2[i+len1]-'a']++; //后移尾
        
            //每次后移一步都要看看匹配了吗
            if(v1==v2)
                return true;
        }
        return false;
    }
};

猜你喜欢

转载自blog.csdn.net/m0_38033475/article/details/92379743