栈与队列(

模拟栈

实现一个栈,栈初始为空,支持四种操作:

  1. push x – 向栈顶插入一个数 x𝑥;
  2. pop – 从栈顶弹出一个数;
  3. empty – 判断栈是否为空;
  4. query – 查询栈顶元素。

现在要对栈进行 𝑀 个操作,其中的每个操作 3 和操作 4 都要输出相应的结果。

int e[N];//用来存储栈里面的元素
int tt;//用来表示栈顶

1.Push函数(插入元素功能)

void Push(int x){
e[++tt] = x;
}

就是在e[]中插入一个新的元素。

 2.Pop函数(从栈顶弹出一个数)

void Pop(){
tt--;
}

就是相当于栈顶减一。

3.Empty函数(判断栈里面是否为空)

bool Empty(){
if (tt > 0)
return false;
else
return true;
}

如果此时栈顶不为0,说明栈里面有元素。

4.Query函数(返回栈顶元素)

int Query(){
return e[tt];
}

返回栈顶元素。

单调队列

对于队列,最经典的题目就是滑动窗口。

给定一个大小为 n≤1000000 的数组。

有一个大小为 𝑘 的滑动窗口,它从数组的最左边移动到最右边。

你只能在窗口中看到 𝑘 个数字。

每次滑动窗口向右移动一个位置。

以下是一个例子:

该数组为 [1 3 -1 -3 5 3 6 7],𝑘 为 3。

窗口位置最小值最大值
[1 3 -1] -3 5 3 6 7-13
1 [3 -1 -3] 5 3 6 7-33
1 3 [-1 -3 5] 3 6 7-35
1 3 -1 [-3 5 3] 6 7-35
1 3 -1 -3 [5 3 6] 736
1 3 -1 -3 5 [3 6 7]37

你的任务是确定滑动窗口位于每个位置时,窗口中的最大值和最小值。

暴力做法

int k;
int a[N];
for (int i = 0;i<n-k+1;++i){
int min = a[i]; 
int max = a[i];
for (int j = i+1;j<i+k:++j){
if (a[j] <=min)
min = a[j];
if (a[j]>=max)
max = a[j];
}
cout << a[i] << a[j] << endl;
}

观察暴力做法,我们可以发现有可以优化的地方。

结合代码来说(以求最小值为例)

int hh = 0,tt = -1;
for (int i = 0;i< n;++i){
    if (hh <= tt && q[hh] < i-k+1)
    hh++;
    while(hh <= tt && a[q[tt]]>= a[i])
    tt--;
    q[++tt] = i;
    if (i+1>=k)
    cout << a[q[hh]] << " ";
}

 代码中的hhtt可以理解为

hh代表一个指向队头元素的指针,tt代表一个指向队尾元素的指针。

而定义的两个数组a[N]和q[N],a[N]用来存储每一个元素的值,q[N]用来存储没有剔除过后的元素的下标。那么

q[tt]就可以理解为经过删除操作后的队列中队尾元素的下标,q[hh]就可以理解为队头元素的下标。

分析代码:

1.更新队头元素,防止队头元素出队列。

if (hh <= tt && q[hh] < i-k+1)
    hh++;

 2.比较队尾元素和要插入的值

while(hh <= tt && a[q[tt]]>= a[i])
    tt--;

画张图来看

tt--;
q[++tt] = i;

 认为此时tt是指向队尾元素的指针,指针自减,表示删除此时的队尾元素,而后q[++tt] = i,为队尾元素的下标重新赋值,相当于更改了队尾元素的下标,画张图更好理解

3.判断队列是否完全进入数组 ,输出最小值

if (i+1>k)
cout<< a[q[hh]] << " ";

上图

同时在q[N]数组中存储着剔除后的数组元素的下标 ,而这些下标在数组a[N]中对应的元素应该呈单调递增的趋势,因此对于每一个队列,只要输出a[q[hh]],输出队头元素,就是这个队列的最小值。

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值