Bootstrap

3297 统计重新排列后包含另一个字符串的子字符串数目

通过示例我们可以看出,只要子串内包含第二个字符串的所有字符,它就是一个合法的子字符串

1.列出所有的子串,再从子串中一一查找

class Solution {
public:
    long long validSubstringCount(string word1, string word2) {
        long long n=word1.size();
        long long m=word2.size();
        long long character[26]={0}; //统计word2中的字符出现的次数
        long long result=0;
        for(int i=0;i<m;i++){
            character[word2[i]-'a']++;
        }

        //使用前缀和数组统计到index为止,所有字符出现的次数
        long long presum[n][26];
        memset(presum, 0, sizeof(presum));
        for(int i=0;i<n;i++){
            for(int j=i;j<n;j++){
                presum[j][word1[i]-'a']++;
            }
        }
        for(int i=0;i<n;i++){
            for(int j=i;j<n;j++){//统计子串为i到j的字符
                bool flag=true;
                for(int k=0;k<26;k++){
                    if(i>0){
                        if(presum[j][k]-presum[i-1][k]<character[k]){
                            flag=false;
                            break;
                        }
                    }
                    else{
                        if(presum[j][k]<character[k]){
                            flag=false;
                            break;
                        }
                    }
                     
                }
                if(flag) result++;
            }
        }
        return result;
    }
};

代码的复杂度到了O(n^3),不出意外的超时了。

2.滑动窗口

我们使用left,right作为左右边界

假设当前left 和right所框定的边界可以满足要求,那么我们把right往右移动后也一定可以满足要求,那么从字符串的右侧到right的所有字符串都应该被统计。此时我们再把窗口的左边界left往右移动,判断是否仍然满足。

如果当前left 和right所框定的边界不能满足要求,我们把right往右移,这样新加入字符才可能使得框定的边界满足要求

class Solution {
public:
    bool Is_satisfied(long long (&source_character)[26],long long (&windows_character)[26]){
        bool flag=true;
        for(int i=0;i<26;i++){
            if(windows_character[i]<source_character[i]){
                flag=false;
                break;
            }
        }
        return flag;
    }
    long long validSubstringCount(string word1, string word2) {
        int n=word1.size();
        int m=word2.size();
        long long source_character[26]={0};
        long long windows_character[26]={0};
        long long result=0;
        for(int i=0;i<m;i++){
            source_character[word2[i]-'a']++;
        }
        int left=0,right=-1;
        
        while(right<n){
            if(Is_satisfied(source_character,windows_character)){
                result+=(n-right);//加上右窗口到原字符串右边界的所有字符串
                windows_character[word1[left]-'a']--;//减去左窗口的字符
                left++;//左窗口右移
            }
            else{
                right++;
                if(right>= n) break;
                windows_character[word1[right]-'a']++;
            }
        }
        return result;
    }
};
;