滑动窗口算法思想图解说明

滑动窗口算法

滑窗思想在解决一些联系子数组问题上被广泛应用,遇到对一些给定长度的子数组序列进行操作  或者求解子串问题,首先想到滑窗技巧

  • 滑窗思想模板

最为经典的滑窗算法有其固定的解题模板

下面就通过一段伪代码的形式对滑窗思想进行阐述

int left = 0, right = 0;

while (right < s.size()) {
    // 增大窗口
    window.add(s[right]);
    right++;

    while (window needs shrink) {
        // 缩小窗口
        window.remove(s[left]);
        left++;
    }
}
  • 滑窗思想应用

接下来通过几道算法题目对滑窗思想进行应用

  • 对定长子数组操作

  • (1)子数组的最大平均值

double findMaxAverage(int* nums, int numsSize, int k)
{     
    int arrsum=0;     //先前 k 个元素作为一个窗口     
    for(int i=0;i<k;i++)     
    {         
        arrsum+=nums[i];     
    }     
    int maxsum=arrsum;     //滑动窗口滑动     
    for(int i=k;i<numsSize;i++)     
    {         
        arrsum=arrsum-nums[i-k]+nums[i];         
        maxsum=arrsum>maxsum?arrsum:maxsum;     
    }     
    return (double)maxsum/k; 
} 
 

根据定长滑窗,计算前k个数值所组成滑窗的和大小,k个为一组向后滑动即可,每次减去窗口前一个元素,加上窗口后一个元素实现窗 口后移查找.

举例说明:考虑数组arr [] = { 5,2,-1,0,3 },k = 3

基本上依靠模板进行滑窗移动,左右边界作为滑窗边界,

左边界左移,以及右边界右移  导致滑窗尺寸变大

左边界右移,以及右边界左移  导致滑窗尺寸变小

  • (2)滑动窗口的最大值

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int>res;
        if(nums.size()==0)
        {
            return res;
        }
        int n=nums.size()-k+1;//窗口数
        int t=-1;//当前窗口最大值下标
        int max;//当前窗口最大值

        for(int i=0;i<n;i++)
        {
            if(t<i)//上个滑窗最大值不在当前窗口里 重新遍历查找
            {
                max=nums[i];
                for(int j=i+1;j<i+k;j++)
                {
                    if(nums[j]>max)
                    {
                        t=j;
                        max=nums[j];
                    }
                }
            }
            else//上个滑窗最大值在当前窗口里
            {
                if(nums[i+k-1] >= max)//注意,此时滑动窗口移动,只新增一个数 只需要与新增的数比较即可
                {
                    t = i+k-1;
                    max = nums[i+k-1];
                }
            }
            res.push_back(max);
        }
        return res;
    }
};

对于定长滑窗,可以根据整个数组长度以及滑窗长度,确定滑窗个数nums.size()-k+1

  • 最大子序和

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        if(nums.size()==0)
        {
            return 0;
        }
        int left=0;//滑窗  左边界索引
        int right=0;//滑窗 右边界索引

        int cursum=nums[0];//记录当前滑窗和
        int maxsum=nums[0];

        while(left<=right&&right<nums.size()-1)
        {
            right++;
            if(cursum<0&&cursum<nums[right])
            {
                //当前滑窗和<滑窗右边界单值  或者当前滑窗为负数  需要更新左边界 重新确定滑窗
                left=right;
                cursum=0;//当前滑窗和 归零
            }
            cursum+=nums[right];
            maxsum=maxsum>cursum?maxsum:cursum;//根据大小关系 关系maxsum
        }
        return maxsum;
    }
};
  • 对于子串的操作

class Solution {
public:
    int lengthOfLongestSubstring(string s) {
        int left = 0, right = 0;
        unordered_map<char, int> window;//创建哈希表存储 方便统计重复元素
        int res = 0; // 记录最长长度

        while (right < s.size()) {
            char c1 = s[right];
            window[c1]++;
            right++;
            // 如果 window 中出现重复字符
            // 开始移动 left 缩小窗口
            while (window[c1] > 1) {
                char c2 = s[left];
                window[c2]--;
                left++;
            }
            res = max(res, right - left);//根据当前滑窗边界差值长度对res进行更新
        }
    return res;
    }
};

举例说明:“pwwkew”

  • 6
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HT . WANG

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值