当前位置:   article > 正文

算法思想总结:滑动窗口算法

算法思想总结:滑动窗口算法

                                                      创作不易,感谢三连 

一.长度最小的数组

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

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

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

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

  1. class Solution {
  2. public:
  3. int lengthOfLongestSubstring(string s)
  4. {
  5. int hash[128]={};//计数
  6. int len=0, n=s.size();
  7. for(int left=0,right=0;right<n;++right)
  8. {
  9. ++hash[s[right]];//进窗口
  10. while(hash[s[right]]>1) --hash[s[left++]];//出窗口
  11. len=max(len,right-left+1);//更新长度
  12. }
  13. return len;
  14. }
  15. };

三.最大连续1的个数

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

  1. class Solution {
  2. public:
  3. int longestOnes(vector<int>& nums, int k)
  4. {
  5. int len=0;
  6. for(int left=0,right=0,zero=0;right<nums.size();++right)
  7. {
  8. if(nums[right]==0) ++zero;//进窗口
  9. while(zero>k) if(nums[left++]==0) --zero;//出窗口
  10. len=max(len,right-left+1);
  11. }
  12. return len;
  13. }
  14. };

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

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

  1. class Solution {
  2. public:
  3. int minOperations(vector<int>& nums, int x)
  4. {//将问题转化为求一个最长子数组 其大小正好==sum-x
  5. int ret=-1;
  6. int sum=accumulate(nums.begin(),nums.end(),0);//计算数组的总和
  7. int target=sum-x;//记录目标值
  8. if(target<0) return -1;//细节处理
  9. for(int left=0,right=0,temp=0,n=nums.size();right<n;++right)
  10. {
  11. temp+=nums[right];//进窗口
  12. while(temp>target) temp-=nums[left++];//出窗口
  13. if(temp==target) ret=max(ret,right-left+1);//更新结果
  14. }
  15. return ret==-1?-1:nums.size()-ret;
  16. }
  17. };

 五.水果成篮

. - 力扣(LeetCode)水果成篮

  1. class Solution {
  2. public:
  3. int totalFruit(vector<int>& fruits)
  4. {
  5. int hash[100001]={0};
  6. int ret=0,n=fruits.size();
  7. for(int left=0,right=0,kinds=0;right<n;++right)
  8. {
  9. if(hash[fruits[right]]++==0) ++kinds;//进窗口
  10. while(kinds>2) if(--hash[fruits[left++]]==0) --kinds;
  11. ret=max(ret,right-left+1);
  12. }
  13. return ret;
  14. }
  15. };

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

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

  1. class Solution {
  2. public:
  3. vector<int> findAnagrams(string s, string p)
  4. {
  5. vector<int> ret;
  6. int hash1[26]={0};//用来统计p的元素个数
  7. for(char ch:p) ++hash1[ch-'a'];
  8. int hash2[26]={0};//用来统计滑动窗口的元素个数
  9. int m=p.size();
  10. for(int left=0,right=0,count=0;right<s.size();++right)//count用来记录有效字符的个数
  11. {
  12. char in=s[right];
  13. if(++hash2[in-'a']<=hash1[in-'a']) ++count;//进窗口的同时统计有效字符个数
  14. if(right-left+1>m)//判断 出窗口
  15. {
  16. char out=s[left++];
  17. if(hash2[out-'a']--<=hash1[out-'a']) --count;
  18. }
  19. if(count==m) ret.push_back(left);
  20. }
  21. return ret;
  22. }
  23. };

七.最小覆盖字串

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

  1. class Solution {
  2. public:
  3. string minWindow(string s, string t)
  4. {
  5. int hash1[128]={0};//统计t字符串个元素的出现次数
  6. int kinds=0;//用来统计种类
  7. for(char ch:t) if(hash1[ch]++==0) ++kinds;
  8. int hash2[128]={0};//统计s字符串中滑动窗口的元素出现次数
  9. int begin=-1,minlen=INT_MAX;//用来记录返回值情况
  10. for(int left=0,right=0,count=0;right<s.size();++right)
  11. {
  12. if(++hash2[s[right]]==hash1[s[right]]) ++count;//进窗口的同时统计窗口内元素种类
  13. while(count==kinds)//当种类都一样时,可以去更新结果
  14. {
  15. if(right-left+1<minlen)//因为还需要更新begin,所以不能直接用min
  16. {
  17. minlen=right-left+1;
  18. begin=left;
  19. }
  20. if(hash2[s[left]]--==hash1[s[left]]) --count;
  21. ++left;
  22. }
  23. }
  24. return begin==-1?"":s.substr(begin,minlen);
  25. }
  26. };

 八.串联所有单词的子串

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

 

  1. class Solution {
  2. public:
  3. vector<int> findSubstring(string s, vector<string>& words)
  4. {
  5. int m=words.size();//单词个数
  6. int len=words[0].size();//每个单词的长度
  7. vector<int> ret;//用来返回
  8. unordered_map<string,int> hash1;//用来记录word的各个单词出现次数
  9. for(auto s:words) ++hash1[s];
  10. for(int i=0;i<len;++i)//要使用len次滑动窗口
  11. {
  12. unordered_map<string,int> hash2;//用来记录滑动窗口的各个单词出现次数
  13. for(int left=i,right=i,count=0;right+len-1<s.size();right+=len)//count用来有效子串
  14. {
  15. string in=s.substr(right,len);
  16. if(++hash2[in]<=hash1[in]) ++count;//进窗口顺便维护count
  17. if(right-left+1>len*m)//如果超过窗口的大小,就要出窗口
  18. {
  19. string out=s.substr(left,len);
  20. if(hash2[out]--<=hash1[out]) --count; //出窗口前要先维护count
  21. left+=len;//出窗口要更新left
  22. }
  23. if(count==m) ret.push_back(left);//如果count==m,说明有效子串达到要求
  24. }
  25. }
  26. return ret;
  27. }
  28. };

九.滑动窗口总结

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

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

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

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/337273
推荐阅读
相关标签
  

闽ICP备14008679号