滑动窗口算法

1、算计简介

  • 滑动窗口,即有一个大小可变的窗口,左右两端方向一致地向前滑动

2、适用范围

  • 一般是字符串和列表
  • 一般求最值或子序列

3、算法思想

  • 适用双指针,初始化left=right=0,将索引闭区间[left,riht]称为一个窗口
  • 先不断地增加right指针扩大窗口[left,right],直到窗口中的序列符合要求
  • 此时,停止增加right,转而不断增加left指针缩小窗口[left,right],直到窗口中的序列不再符合要求。同时,每次增加left前,都要更新一轮结果
  • 重复2和3,直到right到达序列的尽头

ps:第2步找到可行解,第3步优化这个解

4、算法模板

int left=0,right=0;

while(right未越界)

{

  更新需要维护的变量;

  ---

  情况1:窗口大小固定

  //如果题目的窗口固定:需要判断当前窗口长度是否达到了限制长度窗口

  //左指针移动一个单位,从而保证下一次右移时窗口长度不变;

  //左指针移动前先更新需要维护的变量

  if(窗口长度达到了限定长度)

  {

    更新维护变量;

    窗口左指针右移一个单位,保证下一次右移时窗口长度不变;

  }

  ---

  情况2:窗口大小不固定

  //此时需要考虑窗口是否合法

  //如果当前窗口不合法,用一个while去不断低移动左指针,从而剔除非法元素直到窗口再次合法

  //在左指针移动之前更新维护变量

  while(不合法)

  {

    更新维护变量;

    不断移动窗口左指针直到窗口再次合法;

  }

  return ...

}

5、例题

子数组最大平均数

题目描述:

给你一个由 n 个元素组成的整数数组 nums 和一个整数 k

请你找出平均数最大且 **长度为 **k 的连续子数组,并输出该最大平均数。

任何误差小于 10-5 的答案都将被视为正确答案。
解答

class Solution{
 public:
     double findMaxAverage(vector<int>& nums,int k)
     {
       //滑动窗口长度不变
       //step 1
       //本题求最大平均值(其实就是求最大和),需要定义sum_,max_avg
       int sum=0,n=nums.size();
       double max_avg=0.0;
       //step 2
       //定义滑动窗口的首尾端,然后滑动
       int right=0,maxSum;
       for(;right<k;right++)
         sum+=nums[right];
       maxSum=sum;
       for(right=k;right<n;right++)
       {
         sum=sum-nums[right-k]+nums[right];
         maxSum=max(maxSum,sum);
       }
       return (double)maxSum/k;//强制转换,保证浮点型输出
     }
}

无重复字符的最长子串

题目描述:
给定一个字符串s,请你找出其中不含有重复字符的最长子串的长度

解答

class Solution
{
  public:
    int lenghthOfLongestSubstring(string s)
    {
      //step 1:定义需要维护的变量,本题求最大长度,需要定义max_len
      //本题涉及去重,需要定义无需集合set
      if(s.size()==0)
        return 0;
      int max_len=0;
      unordered_set<char> lookup;//定义无序集合
      int left=0;
      for(int i=0;i<s.size();i++)
      {
        //step 2:检查窗口是否合法
        //如果新加入的元素已经存在,则不合法,删除最左边的元素
        while(lookup.find(s[i])!=lookup.end()){
          lookup.erase(s[left]);//删除最左边的元素
          left++;
        }
        max_len=max(max_len,i-left+1);
        lookup.insert(s[i]);
        }
        
        return len_max;
    }
}

至多包含两个不同字符的最长子串

题目描述:
给定一个字符串,找出至多包含两个不同字符的最长子串t
示例:

输入: "eceba"
输出: 3
解释: t 是 "ece",长度为3

解答:

class Solution{
  public:
  int lengthOfLongestSubstringTwoDistinct(string s)
  {
    //step 1:定义需要维护的变量,本题求最多包含两个不同的最长子串,还需要定义不同的字母个数
    int left=0,right=0;
    int cnt=0;
    int maxlen=0;
    unordered_map<char> m;
    //step 2:移动指针,并考虑窗口是否合法
    for(;right<s.size();right++)
    {
      if(m[s[right]]==0)//出现新字符
        cnt++;
      m[s[right]]++;//计数加1
      while(cnt>2)//窗口大于2
      {
        m[s[left]]--;
        if(m[s[left++]]==0)
          cnt--;
      }
    }
    
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值