创作不易,感谢三连 

一.长度最小的数组

. - 力扣(LeetCode)长度最小的数组

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) 
    {
           int len=INT_MAX,n=nums.size(),sum=0;//len必须要给一个很大的数,否则
           for(int left=0,right=0;right<n;++right){
            sum+=nums[right];//right进窗口
            while(sum>=target){ //符合条件后进行更新,然后出窗口
                len=min(len,right-left+1);//更新长度
                sum-=nums[left++];
            }
           }
           return len==INT_MAX?0:len;
    }
};

 二.无重复字符的最长字串

. - 力扣(LeetCode)无字符的最长字串

class Solution {
public:
    int lengthOfLongestSubstring(string s) 
    {
        int hash[128]={};//计数
        int len=0, n=s.size();
        for(int left=0,right=0;right<n;++right){
            ++hash[s[right]];//进窗口
            while(hash[s[right]]>1)  
               --hash[s[left++]];//出窗口
            len=max(len,right-left+1);//更新长度
        }
        return len;
    }
};

三.最大连续1的个数

. - 力扣(LeetCode)最大连续1的个数

class Solution {
public:
    int longestOnes(vector<int>& nums, int k)
    {
         int len=0;
         for(int left=0,right=0,zero=0;right<nums.size();++right){
                if(nums[right]==0) ++zero;//进窗口
                while(zero>k) 
                   if(nums[left++]==0) --zero;//出窗口
                len=max(len,right-left+1); 
            }
            return len;
    }
};

 四.将x减到0的最小操作数

. - 力扣(LeetCode)将x减到0的最小操作数

class Solution {
public:
    int minOperations(vector<int>& nums, int x) {
        int n=nums.size();
        // 找到一个最长子数组和恰好为sum-x
        int ret=-1;
        int sum=accumulate(nums.begin(),nums.end(),0);
        int target=sum-x;//目标值
        if(target<0) return -1;
        for(int left=0,right=0;right<n;++right){
            target-=nums[right];
            while(target<0) target+=nums[left++];
            if(target==0) ret=max(ret,right-left+1);
        } 
        return ret==-1?-1:n-ret;
    }
};

 五.水果成篮

. - 力扣(LeetCode)水果成篮

class Solution {
public:
//最长子数组,但是不能超过两个种类
    int totalFruit(vector<int>& nums) {
        int n=nums.size();
        int ret=1;
        unordered_map<int,int> hash;//用来保存每种水果的数量
        for(int left=0,right=0,kind=0;right<n;++right){
            if(hash[nums[right]]++==0) ++kind;
            while(kind>2) 
              if(--hash[nums[left++]]==0) --kind;
            ret=max(ret,right-left+1);
        }
        return ret;
    }
};

六.找到字符串种所有字母异位词

. - 力扣(LeetCode)找到字符串种所有字母异位词

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> ret;
        int m=s.size(),n=p.size();
        int hash1[26]={};//用来统计s
        int hash2[26]={};//用来统计p
        for(auto&e:p) ++hash2[e-'a'];
        for(int left=0,right=0,count=0;right<m;++right){
            char in=s[right];
            if(++hash1[in-'a']<=hash2[in-'a']) ++count;//统计总字符数
            //因为窗口是不变的
            if(right-left+1>n){//用来维持窗口固定大小,left一定要出
             char out=s[left++];
             if(hash1[out-'a']--<=hash2[out-'a']) --count; //我比你小说明我是合法的
            }
            if(count==n) ret.emplace_back(left);
        }
        return ret;
    }
};

七.最小覆盖字串

. - 力扣(LeetCode)最小覆盖字串

class Solution {
public:
    string minWindow(string s, string t) {
        int m=s.size(),n=t.size();
        int hash1[128]={};//用来统计s的字符个数
        int hash2[128]={};//用来统计t的字符个数
        int kinds=0;//统计有哪些种类  该题不能统计数量,因为可能会出现很多一样的
        for(auto&e:t) 
            if(hash2[e]++==0) ++kinds;
        int begin=-1,minlen=INT_MAX;//需要记录区间
        for(int left=0,right=0,count=0;right<m;++right){
            char in =s[right];
            if(++hash1[in]==hash2[in]) ++count;//说明凑齐这个种类了
            while(kinds==count){//当种类都凑齐了说明ok了
                if(right-left+1<minlen){
                    begin=left;
                    minlen=right-left+1;
                }
                char out=s[left++];//出窗口
                if(hash1[out]--==hash2[out]) --count;//正好相等的时候说明种类少了一种
            }
        }
        return begin==-1?"":s.substr(begin,minlen);
    }
};

 八.串联所有单词的子串

. - 力扣(LeetCode)串联所有单词的子串

class Solution {
public:
    vector<int> findSubstring(string s, vector<string>& words) {
         int m=words.size(),len=words[0].size();//前者是单词种类,后者是一个单词的长度(决定窗口大小)
         vector<int> ret;//结果集
         unordered_map<string,int> hash1;//统计words
         for(auto&str:words) ++hash1[str];
         for(int i=0;i<len;++i){
            unordered_map<string,int> hash2;//统计s
            for(int left=i,right=i,count=0;right+len-1<s.size();right+=len){
                string in=s.substr(right,len);
                if(++hash2[in]<=hash1[in]) ++count;
                if(right-left+1>len*m){//这时候得出了
                    string out=s.substr(left,len);
                    if(hash2[out]--<=hash1[out]) --count;
                    left+=len;
                }
                if(count==m) ret.emplace_back(left);
            }
         }
         return ret;
    }
};

九.滑动窗口总结

   当题目涉及到子串或者是子数组,都可以考虑到使用滑动窗口来进行解决

    但是有一个需要注意的地方就是如果涉及到窗口求和的话。要保证数都是正整数,否则就不满足单调性。如下图这一题

涉及到不同的种类需要统计数量的时候,常常会用到哈希表!! (5-8题)

后面有类似题目会持续更新!! 

更多推荐