C++滑动窗口最大/最小值

原题链接//https://ac.nowcoder.com/acm/problem/51001

题意:给定一个数组,给你一个长度为k的窗口,窗口每次向右滑动一个位置,求每次滑动后窗口里最大/最小的数。

示例:

示例
思路1:优先队列

最大值:维护一个长度为k的优先队列(pair类型,pair类型的优先队列排序是先按照first排序,再按照second序),那我们就可以定义一个priority_queue<pair<a[i], i> >, 当窗口移动后我们判断队列的头元素的second是否还在窗口中(移动窗口后,以前的元素可能已不再窗口内), 若在就将新元素加入到队列中,若不在就先将队首出列,然后再将新元素加入到队列中。这样每次输出队列的首元素的first即可。

最小值:同理建一个小顶堆,priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >,可求出每次窗口移动的最小值。

时间复杂度:从前往后遍历每个元素,复杂度为O(n),元素入队的复杂度为O(logn)(堆的操作为O(logn)),总复杂度为O(nlogn)

代码

priority_queue<pair<int,int> > pq1;   //大顶堆
priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > > pq2;   //小顶堆
vector<int> v1, v2;   //存储最大值  最小值
void Sliding_Window(int a[], int n, int k)
{
    
    
    for(int i=1;i<=n;i++)
    {
    
    
        while(!pq2.empty() && (pq2.top().second)<=i-k)   //队首不在窗口内  出队
            pq2.pop();
        pq2.push(pair<int,int>(a[i],i));   //入队
        while(!pq1.empty() && (pq1.top().second)<=i-k)
            pq1.pop();
        pq1.push(pair<int,int>(a[i],i));
        if(i>=k)
        {
    
    
            v2.push_back(pq2.top().first);
            v1.push_back(pq1.top().first);
        }
    }
}

使用优先队列的时间复杂度为O(nlogn),那是否有跟优秀的算法呢,答案是有的,接下来我们来说一下由双端队列解决该问题。

思路2:双端队列

双端队列的优点在与既可以从队首删除,也可以从队尾删除元素。

最大值:我们定义一个双端队列,当队列不空时,每次窗口移动后,将新元素与队列中的元素从后往前比较,将队列中比新元素小的元素删除(只要队列中的元素还在窗口内,且比新元素小,则窗口中最大值必不可能为队列中的元素),在此操作之前同样要将窗口移动后队列中已不在窗口的元素出列,那么每次操作之后队列的首元素既是窗口中的最大值。

最小值:同理将队列中比新元素大的全部删除即可。

时间复杂度:每个元素出队入队一次,出队一次,所以复杂度为O(n)

代码

deque<pair<int,int> > pq1;
deque<pair<int,int> > pq2;
vector<int> v1, v2;
void Sliding_Window(int a[], int n, int k)
{
    
    
    for(int i=1;i<=n;i++)
    {
    
    
        while(!pq2.empty() && (pq2.front().second)<=i-k)  //将不在窗口的元素出队
            pq2.pop_front();
        while(!pq2.empty() && (pq2.back().first>a[i]))   //将比新元素大的元素出队
            pq2.pop_back();
        pq2.push_back(pair<int,int>(a[i],i));
        while(!pq1.empty() && (pq1.front().second)<=i-k)
            pq1.pop_front();
        while(!pq1.empty() && (pq1.back().first<a[i]))
            pq1.pop_back();
        pq1.push_back(pair<int,int>(a[i],i));
        if(i>=k)
        {
    
    
            v2.push_back(pq2.front().first);
            v1.push_back(pq1.front().first);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/Siyue1999/article/details/108929789