【数据结构与算法】双端队列 deque

本文介绍了双端队列deque的概念及其在处理数组问题中的应用,如生成窗口最大值数组和计算最大值减去最小值差值小于等于num的子数组数量。通过对比暴力解法和双端队列解法,展示了deque如何实现更高效的解决方案,时间复杂度分别为O(N)和O(N^2)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

参考《程序员面试指南:IT名企算法于数据结构题目最优解(第2版)》

双端队列deque

普通的队列是先入先出FIFO(First In First Out),只能从队尾添加元素,从队首弹出元素。而双端队列则是从队尾添加元素,但是既可以从队首弹出元素,和普通的队列一样,也可以和栈一样从队尾弹出元素,所以叫双端队列deque(double-ended queue),它同时具备队列(FIFO)和栈(LIFO)的特性。

生成窗口最大值数组

题目描述

有一个整型数组arr和一个大小为w的窗口从数组的最左边滑到最右边,窗口每次向右边滑一个位置。如果数组长度为n,窗口大小为w,则一共产生n-w+1个窗口的最大值。请实现一个函数。
输入:整型数组arr,窗口大小为w
输出:一个长度为n-w+1的数组resres[i]表示每一种窗口状态下的最大值。

示例
输入:arr = [4,3,5,4,3,3,6,7], w = 3
输出:res = [5,5,5,4,6,7]

暴力解法

时间复杂度为 O ( N × w ) \mathcal{O}(N\times w) O(N×w),遍历arr,每次统计w窗口中的最大值即可。

双端队列解法

时间复杂度为 O ( N ) \mathcal{O}(N) O(N)
大致思路是维护一个从队首到队尾单调递减的双端队列qmax,其中存放着arr中的下标,还有一个res数组。
遍历到arr[i]qmax的更新规则为:

  1. 如果qmax为空,则直接将i放入队尾;
  2. 如果qmax不为空,则需要判断队尾元素j对应arr[j]与当前元素的大小:
    1). 如果arr[j] <= arr[i],则弹出j,继续更新规则;
    2). 如果arr[j] > arr[i],则直接将i添加进队尾。
  3. 如果qmax[0] == i - w,则说明队首元素不再位于w
### 双端队列 Deque 数据结构 #### 定义 双端队列 (Deque, Double-ended Queue) 是一种可以从两端进行插入和删除操作的线性数据结构[^1]。这种特性使得它可以灵活地处理多种类型的队列需求。 #### 基本操作 双端队列支持如下基本操作: - `push_front(x)`:在前端插入元素 x。 - `pop_front()`:移除并返回前端元素。 - `push_back(x)`:在后端插入元素 x。 - `pop_back()`:移除并返回后端元素。 - `empty()`:判断双端队列是否为空。 - `size()`:获取当前存储元素的数量。 这些操作的时间复杂度通常为 O(1),这得益于内部采用的高效实现机制。 #### 实现方式 双端队列可以通过两种主要的方式实现——基于数组或者链表。每种方法都有各自的优劣之处: - **数组实现**:通过动态分配连续内存来模拟双端队列的行为,适合于已知大小范围的情况;但在频繁增删时可能会引发大量的内存复制开销。 - **链表实现**:利用节点之间的指针链接形成双向循环列表,允许任意位置快速插入/删除而不必担心内存重定位问题,更适合未知规模的数据集。 对于 C++ 中的标准库容器 `std::deque` 而言,则采用了分段管理的技术方案,在保持随机访问特性的前提下优化了性能表现[^2]。 然而值得注意的是,由于 `std::deque` 的特殊设计,当涉及到大量遍历操作时,其效率相对较低,因为每次迭代都需要额外检查是否跨越了某个小块区域的边界[^3]。 #### 应用场景 尽管存在上述局限性,双端队列仍然有着广泛的应用领域: - 作为标准模板库(STL)中栈(stack)和队列(queue)的基础实现之一; - 处理需要同时维护最新最旧记录的任务调度算法; - 缓存淘汰策略中的 LRU(Least Recently Used)缓存管理; - 图形界面应用程序的消息传递系统等[^4]。 ```cpp // 创建一个简单的 C++ std::deque 并执行一些基础操作 #include <iostream> #include <deque> int main() { std::deque<int> d; // 插入几个整数到 deque 尾部 for(int i=0; i<5; ++i){ d.push_back(i); } // 输出所有元素 while(!d.empty()){ std::cout << d.front() << ' '; d.pop_front(); } return 0; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值