滑动窗口问题

描述:

  给定一个数组和一个指定长度的窗口,窗口每次滑动一个距离,求窗口在滑动的过程当中每个窗口当中的

最大和最小值。

思路:

  首先想到的是暴力解法,搜索n-k+1个窗口,将每个窗口中的最大和最小值存储起来。此时的时间复杂度为

O(N*K)。该思路的代码如下:

  

#include<iostream>
#include<vector>
using namespace std;

//使用滑动窗口来,在每个滑动窗口当中搜索最大和最下值,时间复杂度为O(N*K)
int main()
{
    int n,k;
    cin>>n>>k;
    vector<int> nums(n,0);
    for(int i=1;i<=n;i++)
        cin>>nums[i-1];
    //逐个窗口查找最大和最小的值
    vector<int> vmax;
    vector<int> vmin;
    int max,min;
    for(int i=0;i<=n-k;i++){
         max=nums[i];
         min=nums[i];
        for(int j=0;j<k;j++)
        {
            if(nums[i+j]>max)
                max=nums[i+j];
            if(nums[i+j]<min)
                min=nums[i+j];
        }
        vmax.push_back(max);
        vmin.push_back(min);
    }
    for(int elem:vmin)
        cout<<elem<<" ";
    cout<<endl;
    for(int elem:vmax)
        cout<<elem<<" ";
    cout<<endl;
    return 0;    
}

  上述方法的时间复杂度较高,考虑采用双端队列的数据结构。从队列的队头和队尾出队,队头存放的元素是当前窗口

最大值的坐标,队头出队时表示当前的最大值已经不在当前的窗口当中的了,队尾出队时是为了保证队头所存放元素的序

号一直为当前窗口中最大元素的序号。

#include<iostream>
#include<deque>
#include<vector>
using namespace std;

//用来存放窗口移动过程当中的最大值序列
vector<int> res;
vector<int> res2;

int getmax(vector<int>& nums,int size)
{
    //双端队列用来保存遍历过程当中产生的最大值
    deque<int> pos;
    //队列当中维持着长度为窗口长度的序列
    for(int i=0;i<nums.size();i++)
    {
        //队头元素的坐标恰好为将要出队元素的坐标
        if(!pos.empty()&&pos.front()==(i-size))
            pos.pop_front();
        //入队当前元素之前出队所有比其小的元素,确保队首的始终为当前窗口的最大值
        while(!pos.empty()&&nums[pos.back()]<nums[i])
            pos.pop_back();
        pos.push_back(i);
        //队列当前的元素,插入了当前的元素后判断的最大值
        if(i>=(size-1))
            res.push_back(nums[pos.front()]);
    }
}

    int getmin(vector<int>& nums,int size)
    {
        deque<int> pos;
        for(int i=0;i<nums.size();i++)
        {
            //判断当前的队头元素是否位于窗口之外
            if(!pos.empty()&&pos.front()==(i-size))
                pos.pop_front();
            //向队列当中插入元素,包含当前元素的窗口当中被弹出的元素不可能为最大值的
            while (!pos.empty()&&nums[pos.back()]>nums[i])
            {
                pos.pop_back();
            }
            pos.push_back(i);
            //从队头当中取出最小值即可
            if(i>=size-1)
                res2.push_back(nums[pos.front()]);
            
        }
    }


int main()
{
    int n,k;
    cin>>n>>k;
    vector<int> nums(n,0);
    for(int i=0;i<n;i++)
        cin>>nums[i];
    getmax(nums,k);
    getmin(nums,k);
    for(auto elem:res2)
        cout<<elem<<" ";
    cout<<endl;
    for(auto elem:res)
        cout<<elem<<" ";
    cout<<endl;
    return 0;
}

  使用了双端队列之后,生成窗口的最大值数组的时间复杂度变成了线性的。

posted @ 2020-04-13 09:30  一只小菜鸡a  阅读(291)  评论(0)    收藏  举报