单调栈、单调队列、双指针(线性复杂度优化)

本文详细介绍了单调栈这一数据结构在解决数组问题中的应用,包括找到序列中每个数左侧或右侧最近的更大或更小的数。通过设置哨兵元素,避免了边界判断。此外,文章还探讨了单调栈如何保持单调递增或递减的性质,并提供了多个实例,如最大矩形直方图问题。同时,文章也提到了双指针在解决数组和矩阵问题中的应用,如寻找特定条件的子序列和统计子矩阵。

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

单调栈

单调栈(模板)

给定一个序列 a a a ,对于 a a a 中的每个数找到在他左(右)边,最近的比他大(小)的数是什么。

例:对于 a a a 中的每个数找到他左边最近的比他小的数是什么,没有输出 -1

       5
	   3 4 2 7 5
ans = -1 3 -1 2 2

栈内一开始放入负无穷,对每个 a [ i ] a[i] a[i] 和栈顶元素判断就行,如果 a [ i ] a[i] a[i] 更小,那么栈顶元素就不是比 $a[i] $ 小的元素,不断弹栈,直到不能弹完为止。


解释单调栈为什么是单调的

指针遍历到 i i i ,有下标 x < y x<y x<y , a [ x ] < a [ i ] a[x] < a[i] a[x]<a[i] 那么 x x x 就是栈中的合法元素,假设,若有 a [ x ] > a [ y ] a[x]>a[y] a[x]>a[y] , a [ y ] a[y] a[y] 比 $a[x] $ 离 a [ i ] a[i] a[i] 更近,所以假设不成立, a [ x ] < a [ y ] a[x] < a[y] a[x]<a[y] 说明栈中元素是单调递增的。

如果要求右边,就从n到1循环。

求最小,就是 a [ i ] < = 栈顶元素 a[i] <= 栈顶元素 a[i]<=栈顶元素 ,哨兵置 -0x3f3f3f3f。

还有一种记忆方法:

stk[++tt] = -0x3f3f3f3f;
fo(i,1,n){ 
    // 一直有-无穷
    while(a[i] <= stk[tt]) // 如果是<=,栈内元素会是严格单调增的
        tt--;
    if(stk[tt] == -0x3f3f3f3f)
        cout<<"-1 ";
    else
        cout<<stk[tt]<<" ";
    stk[++tt]=a[i];
}
int a[N],stk[N],tt;
void solve(){
    cin>>n;
    fo(i,1,n){
        cin>>a[i];
    }
    stk[++tt] = -0x3f3f3f3f;
    fo(i,1,n){ 
        // 一直有-无穷
        while(a[i] <= stk[tt])
            tt--;
        if(stk[tt] == -0x3f3f3f3f)
            cout<<"-1 ";
        else
            cout<<stk[tt]<<" ";
        stk[++tt]=a[i];
    }
}

y总是用栈空不空判断的

int a[N],stk[N],tt;
void solve(){
    cin>>n;
    fo(i,1,n){
        cin>>a[i];
    }
    fo(i,1,n){ 
        // 一直有-无穷
        while(tt && a[i] <= stk[tt])
            tt--;
        if(tt)
            cout<<stk[tt]<<" ";
        else
            cout<<"-1 ";
        stk[++tt]=a[i];
    }
}

131. 直方图中最大的矩形

建议以后都写 加哨兵的写法,不用判断边界

ll pre[N],suf[N];
void solve(){
    while(cin>>n,n){
        tt=0;
        ll ans=0;
        fo(i,1,n)cin>>a[i];
        h[0] = h[n+1] = -1;
        stk[0] = 0;
        fo(i,1,n){
            while(a[i] <= a[stk[tt]]){
                tt --;
            }
            pre[i] = stk[tt];
            stk[++tt] = i;
        }
        tt=0;
        stk[0] = n+1; 
        for(int i=n;i>=1;i--){
            while(a[i] <= a[stk[tt]]){
                tt -- ;
            }
            suf[i]=stk[tt];
            stk[++tt] = i;
        }
        for(int i=1;i<=n;i++){
            cout<<i<<" "<<pre[i]<<" "<<suf[i]<<endl;
            ans = max(ans,(suf[i]-1-(pre[i]+1)+1)*a[i]);
        }
        cout<<ans<<endl;
    }
}

总结:单调栈和单调队列都可以叫 双端队列 , 单调栈可以存值存下标。单调队列为了判断队头何时出队,存数组下标。

152. 城市游戏 (单调栈TRICK题)

N遍直方图中的最大矩形,注意单调栈写带哨兵的

对于每一行,先预处理出up[]来,然后做n遍单调栈。

int n,m;
char a[1100][1100];
int up[1100][1100];
int stk[1100],tt;
int ans;
void work(int x[1100]){
    int l[1100],r[1100];
    // 左边第一个比他小的数,带哨兵的
    x[0] = x[m+1] = -1;
    stk[++tt] = 0;
    for(int i=1;i<=m;i++){
        while(x[i] <= x[stk[tt]])
            tt--;
        l[i] = stk[tt]; // 下标
        stk[++tt]=i;

    }
	tt = 0;
	stk[++tt] = m+1;
    for(int i=m;i>=1;i--){
        while(x[i] <= x[stk[tt]])
            tt--;
        r[i] = stk[tt];
        stk[++tt]=i;
    }
	
    for(int i=1;i<=m;i++){
        ans = max(ans,(r[i]-1-(l[i]+1)+1) * x[i]);
    }
}

void solve(){
    cin>>n>>m;
    fo(i,1,n)fo(j,1,m)cin>>a[i][j];
    fo(i,1,n){
        fo(j,1,m){
            if(a[i][j] == 'R') up[i][j] = 0;
            else{
                up[i][j] = up[i-1][j]+1;
            }
        }
    }
	// 做n遍直方图中的最大矩形。
    fo(i,1,n){
        work(up[i]);
    }
    cout<<ans*3<<endl;
}
int main(){
    solve();
    return 0;
}   

3780. 构造数组

单调栈综合应用。

主要还是思维。

  1. 分析题,发现题目一定是单峰的,单调端点算单峰。
  2. 枚举峰点,左边数值递增,右边递减,两者独立
  3. 假设分界点是 i i i , 考虑将 1 ∼ i 1 \sim i 1i 变成非严格递增的最大和。
    1. 顺序考虑不好考虑,逆序考虑。 a [ i ] = m [ i ] a[i] = m[i] a[i]=m[i] , a [ i − 1 ] = m i n ( m [ i − 1 ] , a [ i ] ) a[i-1] = min(m[i-1],a[i]) a[i1]=min(m[i1],a[i])
    2. 对于 a [ i ] a[i] a[i] 找到他左边第一个小于他的元素的位置 j j j , [ j + 1 , i ] [j+1,i] [j+1,i] 应该和 a [ i ] a[i] a[i] 相等。
    3. 那么之前的呢?一直跳吗? 递推!
    4. L [ i ] L[i] L[i] 表示将 1 ∼ i 1 \sim i 1i 变成递增(非严格)的最大和。
    5. L [ i ] = L [ j ] + ( i − j ) ∗ a [ i ] L[i] = L[j] + (i-j) * a[i] L[i]=L[j]+(ij)a[i]
  4. 同理预处理出 R [   ] R[\ ] R[ ]
  5. 找到分界点,贪心取理论最大值!

注意求 R时,单调栈中的指针是比i指针靠右的,就像求L时,单调栈中的指针比i指针靠左一样!

const int N=1e6+10,M=1e9+7;

ll n,a[N],l[N],r[N];
ll ans[N];
int stk[N],tt;
void solve(){
    cin>>n;
    fo(i,1,n)cin>>a[i];
    // 求每个元素第一个比他小的元素
    tt = 0;
    a[0] = -1;
    stk[++tt] = 0;
    for(int i=1;i<=n;i++){
        while(a[i] <= a[stk[tt]])
            tt--;
        int left = stk[tt];
        l[i] = l[left] + (ll)(i-left)*a[i];
        stk[++tt] = i;
    }
    a[n+1] = -1;
    tt = 0;
    stk[0] = n+1;
    for(int i=n;i>=1;i--){
        while(a[i] <= a[stk[tt]])
            tt--;
        int left = stk[tt];
        // cout<<i<<" "<<left<<endl; 
        r[i] = r[left] + (ll)(left-i)*a[i];
        stk[++tt] = i;
    }
    
    ll res = 0,k;
    for(int i=1;i<=n;i++){
        if(l[i] + r[i] - a[i] > res){
            res = l[i] + r[i] - a[i];
            k = i;
        }
    }
    ans[k] = a[k];
    for(int i=k-1;i>=1;i--){
        ans[i] = min(a[i],ans[i+1]);
    }
    for(int i=k+1;i<=n;i++){
        ans[i] = min(a[i],ans[i-1]);
    }
    for(int i=1;i<=n;i++){
        cout<<ans[i]<<' ';
    }
}

int main(){
    solve();
    return 0;
}   

P1950 长方形

和求最大矩形面积类似,但是我搞不懂怎么算的方案数(真看不懂)
学会了另一种计算图形中长方形的方法,确定两条边,组合数学乘法原理就行。

typedef long long ll;
int n,m,a[1100][1100];
int l[1100],r[1100]; // l表示左边第一个不大于 , r表示右边第一个小于  ans = (i-l)*(r-i)*h
int up[1100][1100];
int stk[N],tt;
ll ans;
void work(int x[]){
	
    tt = 0;
    x[0] = -1;
    stk[++tt] = 0;
    fo(j,1,m){
        while(x[j] < x[stk[tt]])
            tt--;
        l[j] = stk[tt];
        stk[++tt] = j;
    }

    tt = 0;
    x[m+1] = -1;
    stk[++tt] = m+1;
	for(int j=m;j>=1;j--){
        while(x[j] <= x[stk[tt]])
            tt--;
        r[j] = stk[tt];
        stk[++tt] = j;
    }
    
    // fo(i,1,m)cout<<l[i]<<" ";
    // cout<<endl;
    
    fo(i,1,m){
    	ans += (i-l[i]) * (r[i] - i) * (x[i]);
    }
}

void solve(){
    cin>>n>>m;fo(i,1,n)fo(j,1,m){char s;cin>>s;if(s=='.')a[i][j]=1;else a[i][j]=0;}
    fo(i,1,n){
        fo(j,1,m){
            if(a[i][j]){
                up[i][j] = up[i-1][j]+1;
            }
            else up[i][j] = 0;
        }
    }
    fo(i,1,n){
        work(up[i]);
    }
    cout<<ans;
}

int main(){
    solve();
    return 0;
}   

双指针

4483. 格斗场

排序后发现,当前数会被后边的数删掉,并且当前数的存在不影响后边的数。

对于 i i i 1 ≤ a [ j ] − a [ i ] ≤ k 1 \le a[j]-a[i] \le k 1a[j]a[i]k j j j , 可以找最小的 a [ j ] > a [ i ] + k a[j] > a[i]+k a[j]>a[i]+k , 判断 a [ j − 1 ] − a [ i ] a[j-1] - a[i] a[j1]a[i] 是否大于1。

法一:upper_bound。

int n,k,a[N];
void solve(){
    cin>>n>>k;
    fo(i,1,n)cin>>a[i];
    sort(a+1,a+n+1);
    int ans=0;
    for(int i=1;i<=n;i++){
        int j = upper_bound(a+1,a+n+1,a[i]+k)-a;
        if(a[j-1] - a[i] >=1) ans ++;
    }
    cout<<n-ans;
}

法二:双指针。

原来双指针while中 j 的限制可以绝对 i和j哪个是尾指针,哪个是头指针

证明正确性:

一般双指针都是找4个指针,然后找一个矛盾。

枚举到 i i i ,有 j j j 满足 a [ j ] > a [ i ] + k , a [ j ] 最小 a[j] > a[i] +k,a[j]最小 a[j]>a[i]+k,a[j]最小 i i i 向右移动到了 i ′ i' i ,假设有 j ′ < j j' < j j<j ,和 i ′ i' i 配对。

发现 a [ j − 1 ] − a [ i ] ≤ k a[j-1]-a[i] \le k a[j1]a[i]k 有, a [ j − 1 ] − a [ i ′ ] ≤ k a[j-1]-a[i'] \le k a[j1]a[i]k , 所以 i ′ i' i 对应的 J J J 最小也是 j j j 不是 j ′ j' j ,矛盾,说明, i i i 向右过程中 , j j j 也是单调向右的。

int n,k,a[N];
void solve(){
    cin>>n>>k;
    fo(i,1,n)cin>>a[i];
    sort(a+1,a+n+1);
    // 42 53 54 55 101 101 102
    int ans=0;   
    for(int i=1,j=1;i<=n;i++){
        while(j<=n && a[j] - a[i] <=k){
            j++;
        }
        if(a[j-1] - a[i] >=1) ans ++;
    }
    cout<<n-ans;
}

4405. 统计子矩阵


给定一个 N × M N×M N×M 的矩阵 A A A,请你统计有多少个子矩阵 (最小 1 × 1 1×1 1×1,最大 N × M N×M N×M) 满足子矩阵中所有数的和不超过给定的整数 K K K

对于 100 100% 100 的数据, 1 ≤ N , M ≤ 500 ; 0 ≤ A i j ≤ 1000 ; 1 ≤ K ≤ 250000000 1≤N,M≤500;0≤A_{ij}≤1000;1≤K≤250000000 1N,M500;0Aij1000;1K250000000


二维数组一维化的TRICK题。

矩阵由左上角和右下角确定,一共四个自由度。枚举矩阵上下边界,确定 x 1 , x 2 x1,x2 x1,x2 还剩两个自由度。

问题转化为,一个 一维数组 有多少段连续元素和不超过 K K K

双指针分析:

双指针考虑 [ j , i ] [j,i] [j,i] ,定义 j = f [ i ] j = f[i] j=f[i] j j j 表示 以 i i i 为右端点的距离 i i i 最远的满足条件的 j j j

到这我竟然还不会计数 a n s + = i − j + 1 ans += i-j+1 ans+=ij+1

如果 i i i 固定, j j j 单调向左/右移动,双指针成立,即可将两个自由度优化成一个。

显然成立,反证法 [ j , i ] [j,i] [j,i] 同时向右移动。

/*
A: 10min
B: 20min
C: 30min
D: 40min
*/ 
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <vector>
#include <assert.h>
#include <sstream>
#define pb push_back 
#define all(x) (x).begin(),(x).end()
#define mem(f, x) memset(f,x,sizeof(f)) 
#define fo(i,a,n) for(int i=(a);i<=(n);++i)
#define fo_(i,a,n) for(int i=(a);i<(n);++i)
#define debug(x) cout<<#x<<":"<<x<<endl;
#define endl '\n'
using namespace std;
//#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math,O3")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")

template<typename T>
ostream& operator<<(ostream& os,const vector<T>&v){for(int i=0,j=0;i<v.size();i++,j++)if(j>=5){j=0;puts("");}else os<<v[i]<<" ";return os;}
template<typename T>
ostream& operator<<(ostream& os,const set<T>&v){for(auto c:v)os<<c<<" ";return os;}
template<typename T1,typename T2>
ostream& operator<<(ostream& os,const map<T1,T2>&v){for(auto c:v)os<<c.first<<" "<<c.second<<endl;return os;}
template<typename T>inline void rd(T &a) {
    char c = getchar(); T x = 0, f = 1; while (!isdigit(c)) {if (c == '-')f = -1; c = getchar();}
    while (isdigit(c)) {x = (x << 1) + (x << 3) + c - '0'; c = getchar();} a = f * x;
}

typedef pair<long long ,long long >PII;
typedef pair<long,long>PLL;

typedef long long ll;
typedef unsigned long long ull; 
const int N=1e6+10,M=1e9+7;

int n,m,k;
int a[510][510],sum[510][510];
void solve(){
    cin>>n>>m>>k;
    fo(i,1,n)fo(j,1,m)cin>>a[i][j];
    fo(j,1,m){
        fo(i,1,n){
            sum[i][j] = sum[i-1][j] + a[i][j];
        }
    }
    ll ans = 0;
    fo(x1,1,n){
        fo(x2,x1,n){
            int S = 0;
            for(int i=1,j=1;i<=m;i++){
                S += sum[x2][i] - sum[x1-1][i];
                while(j<=i && S > k){ // j<=i 表示 [j,i] 只有一个元素也可能合法
                    S-=sum[x2][j] - sum[x1-1][j];
                    j++;
                }
                if(S<=k){
                	ans +=(i-j+1);
                }

            }
        }
    }
    cout<<ans<<endl;

}
int main(){
    solve();
    return 0;
}
<think>首先,用户的问题是关于“双指针队列的实现或应用场景”,具体是关于“双指针队列”。回顾之前的对话和提供的引用:-在系统指令中,用户提到“双指针队列”,这可能在之前的交互中没有直接讨论过。系统指令提到要参考站内引用,包括[^1],[^2],[^3],[^4]。-引用[^2]是关于滑动窗口算法,使用双指针和双向队列。它说:“滑动窗口算法是解决数组和序列中连续子结构问题的有力工具。双指针法和双向队列法作为其两种主要实现方式,各有优势。”用户说:“我想了解双指针队列的实现或应用场景请问双指针队列实现与应用”,这似乎是直接的请求。现在,分析用户的问题:-他们想了解“双指针队列”的实现和应用场景。-在引用中,[^2]直接提到了“双向队列法”作为滑动窗口算法的一种实现方式。但用户说“双指针队列”,这有点模糊。在计算机科学中,“队列”通常指先进先出(FIFO)数据结构。引用[^3]讨论了栈和队列的实现。然而,“双指针队列”可能是个混淆;它可能指的是双指针技术在队列操作中的使用,或是特定于滑动窗口的双端队列。在引用[^2]中,它说“双指针法和双向队列法”,所以我需要澄清:-“双指针”通常用于数组遍历,如两个指针协调工作。-“双向队列”也称为双端队列(deque),两端都支持插入和删除。用户可能结合了这两个概念。他们的问题说“双指针队列”,可能意味着使用双指针实现的队列,或基于双指针技术的队列应用。系统指令要求:-使用$...$和$$...$$用于数学表达式。-中文回答。-生成相关问题。-在回答中引用的段落末尾添加引用标识。-参考之前的引用。结构回答:1.**解释双指针队列的概念**:澄清什么是双指针队列。基于引用,它可能指的是滑动窗口算法中使用双指针或双向队列。2.**实现**:描述实现方式。例如,使用双指针模拟队列操作,或在滑动窗口中使用双端队列。3.**应用场景**:讨论应用。4.**示例代码**:提供一个代码块(如系统示例中所示)来演示实现。5.**相关问题**:生成相关问题。从引用[^2]:“滑动窗口算法是解决数组和序列中连续子结构问题的有力工具。双指针法和双向队列法作为其两种主要实现方式”。所以:-双指针法:使用两个指针标记窗口。-双向队列法:使用一个双端队列来维护窗口中的索引。用户说“双指针队列”,可能意指在滑动窗口中使用双端队列。在回答中,我需要确保引用相关部分:-在解释时,末尾添加引用标识如[^2]。中文回答。大纲回答:-**引言**:简要解释双指针队列。-**实现**:描述如何使用双指针或双端队列实现队列行为,特别是在滑动窗口上下文中。-**应用场景**:给出应用例子。-**代码示例**:提供代码。-**相关问题**:在最后生成相关问题。完整回答结构:1.定义和概念。2.详细实现。3.应用场景。4.代码示例。5.相关问题。确保LaTeX格式正确。</think> 以下是关于“双指针队列”的实现和应用场景的详细解释。我将参考您提供的站内引用(特别是引用[^2])来构建回答,确保内容真实可靠。注意,“双指针队列”可能是一个融合的概念:它通常指在算法中结合“双指针技术”和“队列结构”(如双端队列)来解决特定问题,例如滑动窗口算法中的实现[^2]。以下内容将逐步解释实现细节、应用场景,并提供代码示例和相关问题。 ### 1. 双指针队列的概念 在算法设计中,“双指针队列”不是标准术语,但通常涉及两种常见实现方式: - **双指针法(Two Pointers Technique)**:使用两个指针(如左指针和右指针)标记序列中的窗口边界,通过移动指针来模拟队列行为(如入队和出队操作)。时间复杂度一般为$O(n)$,空间复杂度$O(1)$,适用于连续子结构问题[^2]。 - **双向队列法(Double-ended Queue, Deque)**:使用双端队列数据结构(两端支持插入和删除操作),在滑动窗口中结合指针索引来维护高效操作。时间复杂度优化为$O(n)$,空间复杂度$O(k)$($k$为窗口大小),适用于需要高效查找和删除元素的场景[^2]。 这两种方式共同称为“双指针队列实现”,核心在于平衡时间和空间效率,解决数组或序列问题。 ### 2. 实现细节 双指针队列的实现通常依赖于问题需求,以下是两种方法的逐步描述: #### a. 双指针法实现(模拟队列) 在这种方法中,使用两个指针(left 和 right)定义队列的窗口。指针移动规则模拟队列的FIFO(先进先出)行为: - **核心步骤**: 1. 初始化 left 和 right 指针,均指向序列起始(如数组索引0)。 2. right 指针不断右移(入队操作),扩大窗口。 3. 当窗口超出条件时,left 指针右移(出队操作),收缩窗口。 4. 在移动过程中,实时更新队列状态(如计算窗口内元素和、最大值等)。 - **时间复杂度**:$O(n)$,因每个元素至多被访问两次(一次入队、一次出队)。 - **空间复杂度**:$O(1)$,不依赖额外空间。 - **适用问题**:连续子序列求和、最小覆盖子串等。 例如,求解数组最大连续子序列和的简化伪代码: ```plaintext function max_subarray_sum(arr): left = 0, right = 0, max_sum = 0, current_sum = 0 while right < len(arr): current_sum += arr[right] // 入队(扩大窗口) while current_sum < 0: // 条件触发出队 current_sum -= arr[left] // 出队 left += 1 max_sum = max(max_sum, current_sum) right += 1 return max_sum ``` #### b. 双向队列法实现(基于双端队列) 这种方式使用双端队列(deque)存储索引,并配合指针维护窗口: - **核心步骤**: 1. 初始化一个 deque(如 Java 中的 `ArrayDeque` 或 Python 的 `deque`)和左右指针。 2. right 指针右移:将新元素索引加入 deque 尾部(入队),必要时弹出尾部元素以维护单调性(如单调递减)。 3. left 指针移动时:检查 deque 头部是否在窗口内,否则弹出头部(出队)。 4. deque 存储索引,确保头部元素始终为窗口的极值(最大值或最小值)。 - **时间复杂度**:$O(n)$,每个元素入队和出队各一次。 - **空间复杂度**:$O(k)$,$k$为窗口大小。 - **适用问题**:滑动窗口最大值、最短连续子序列等。 以下是一个完整代码示例(使用 Python),实现滑动窗口最大值问题: ```python from collections import deque def max_sliding_window(nums, k): n = len(nums) if n * k == 0: # 检查空数组 return [] deq = deque() # 双端队列存储索引 result = [] # 使用左指针 i 和隐式右指针 j 控制窗口 for i in range(n): # 当 deq 头部超出窗口时出队(i - k 是窗口左边界) if deq and deq[0] == i - k: deq.popleft() # 出队操作 # 维护 deque 单调递减:弹出小于当前元素的尾部索引 while deq and nums[deq[-1]] < nums[i]: deq.pop() # 弹出尾部 deq.append(i) # 入队当前索引 # 当窗口大小达到 k 时,记录 deq 头部的最大值 if i >= k - 1: result.append(nums[deq[0]]) return result ``` **代码解释**:此代码解决了滑动窗口最大值问题(如 LeetCode 239 题)。在循环中: - `i` 作为隐式右指针,控制窗口右移。 - deque 存储索引,确保头部为当前窗口最大值[^2]。 - 时间复杂度 $O(n)$,远优于简单方法的 $O(nk)$。 ### 3. 应用场景 双指针队列的应用广泛,尤其在高效处理连续数据结构算法中: - **滑动窗口问题**:如求连续子序列的最小长度满足条件(引用[^4]类似问题),或滑动窗口的平均值/总和(如引用[^2]的数组应用)。优势在于低时间复杂度处理大规模数据。 - **字符串匹配**:在子串搜索中,使用双指针模拟队列快速匹配(如引用[^4]所述:“j指针扫描b数组,i指针扫描a数组,若a[i]==b[j]则i后移”)。 - **实时数据处理**:在数据流中维护固定大小的窗口,如计算股票价格的移动平均。 - **图遍历优化**:在BFS(广度优先搜索)中使用双端队列实现(如 Dijkstra 算法的变种),减少时间开销[^2]。 - **与其他数据结构结合**:如引用[^3]的栈和队列混合应用,双指针队列可用于RPN(逆波兰表达式)计算的优化版本。 ### 4. 性能对比 - **双指针法**:内存效率高($O(1)$空间),但无法直接处理窗口内极值查询。 - **双向队列法**:高效查询窗口极值($O(1)$时间),但需额外$O(k)$空间[^2]。 实际选择取决于问题需求:如果问题仅需窗口和,双指针法优先;如果需要极值(如最大值),双向队列法更优。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值