C++ 双向队列———特殊的队列 (WZOI 864 滑动窗口)

一、双向队列是什么

双向队列,顾名思义就是能在双向(队头和队尾)进行操作的一种特殊的队列。如果说队列是一个只能在一端扔东西,在另一端丢东西的容器,那么双向队列就好比一个两端都通的容器,既可以在头部扔进东西,在尾部倒出东西;也能在尾部扔进东西,在头部倒出东西的容器。它支持在队头、队尾插入或删除元素。双向队列和队列不同,它能用operator[]访问元素。

二 、双向队列操作

我们知道队列的定义方法是queue<typename> Variable_Name,Typename代表队列内存储的元素类型,比如queue <int> 就是队列内存储int类型的数据,Variable_Name是队列名;双向队列既然是队列的一种,定义方法肯定差不多。它的定义方法是deque<typename> Variable_Name,Typename代表双向队列内存储的元素类型,比如deque <int> 就是双向队列内存储int类型的数据,Variable_Name是双向队列名。除了queue改成deque以外其他没啥区别。

除此以外,双向队列还有 亿 一些常用操作。主要有:

1.front():返回队首元素,队列为空则无效

2.back():返回队尾元素,队列为空则无效

3.push_back(x):从队尾插入元素x,无返回值

4.pop_back():从队尾弹出元素,无返回值

5.push_front(x):从队头插入元素x,无返回值

6.pop_front():从队头弹出元素,无返回值

7.insert():在指定位置前插入元素(传入元素、迭代器),无返回值

8.erase():在指定位置删除元素(传入迭代器),无返回值

9.empty():判断队列是否为空,为空返回true,不为空返回false

10.size():返回队列中元素个数

和队列相同,在使用这些操作时,需要用句点运算符将操作对象与操作关联起来。比如定义了两个队列deque<int> dq1,dq2;dq1.push(7);就是在dq1的队尾插入元素7,cout << dq2.empty();就是输出dq2是否为空。

三、如何模拟双向队列

和队列差不多,详情请看我的另一篇文章 C++ 队列(WZOI 846 模拟队列),按同样的思路也能用数组模拟,就是插入、删除效率较低。

四、WZOI 864 滑动窗口

滑动窗口

题目描述:

      给你一个长度为N的数组,一个长为K的滑动的窗体从最左移至最右端,你只能见到窗口的K个数,每次窗体向右移动一位,如下表:

Window position

Min value

Max value

[ 1 3 -1 ] -3 5 3 6 7

-1

3

1 [ 3 -1 -3 ] 5 3 6 7

-3

3

1 3 [ -1 -3 5 ] 3 6 7

-3

5

1 3 -1 [ -3 5 3 ] 6 7

-3

5

1 3 -1 -3 [ 5 3 6 ] 7

3

6

1 3 -1 -3 5 [ 3 6 7 ]

3

7

你的任务是找出窗口在各位置时的max value,min value. 

数据范围: 
20%: n<=500; 50%: n<=100000; 
100%: n<=1000000;

输入格式:

第1行n,k,第2行为长度为n的数组

输出格式:

2行,第1行每个位置的min value,第2行每个位置的max value

样例输入:
<span style="color:#212529"><span style="background-color:#f5f5f5">8 3 
1 3 -1 -3 5 3 6 7
</span></span>
样例输出:
<span style="color:#212529"><span style="background-color:#f5f5f5">-1 -3 -3 -3 3 3
3 3 5 5 6 7
</span></span>

时间限制: 1000ms
空间限制: 128MB

这里附上滑动窗口的AC代码(虽然关联不大起码用到了双向队列)。

#include <bits/stdc++.h>
using namespace std;
int a[1000005];
int ans1[1000005], ans2[1000005];
int main(){
    cin.tie(nullptr);
    cout.tie(nullptr);
    ios::sync_with_stdio(false);
    int n, k;
    cin >> n >> k;

    for (int i = 1; i <= n; i++)
        cin >> a[i];

    deque< int > maxq, minq;

    for (int i = 1; i <= k; i++) {
        while (!maxq.empty() && a[maxq.back()] <= a[i])
            maxq.pop_back();

        maxq.push_back(i);

        while (!minq.empty() && a[minq.back()] >= a[i])
            minq.pop_back();

        minq.push_back(i);
    }

    int p = 0;
    ans1[p++] = a[minq.front()];
    ans2[p - 1] = a[maxq.front()];

    for (int i = k + 1; i <= n; i++) {
        while (!maxq.empty() && a[maxq.back()] <= a[i])
            maxq.pop_back();

        maxq.push_back(i);

        while (!minq.empty() && a[minq.back()] >= a[i])
            minq.pop_back();

        minq.push_back(i);

        while (!maxq.empty() && maxq.front() <= i - k)
            maxq.pop_front();

        while (!minq.empty() && minq.front() <= i - k)
            minq.pop_front();

        ans1[p++] = a[minq.front()];
        ans2[p - 1] = a[maxq.front()];
    }

    cout << ans1[0];

    for (int i = 1; i < p; i++)
        cout << ' ' << ans1[i];

    cout << endl;
    cout << ans2[0];

    for (int i = 1; i < p; i++)
        cout << ' ' << ans2[i];

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值