例子:一个数列包含 n 个正整数,请按顺序输出数列中每一个数前面第一个(距离自己最近)比自己大的数。如果不存在这样的数请在对应位置输出 0。
cpp
#include<bits/stdc++.h>
using namespace std;
int s[300001],n,top,ans;
int main()
{
scanf("%d",&n);
top=0;
int t;
for(int i=1;i<=n;i++)
{
scanf("%d",&t);
while(top>=1 && s[top]<=t )
top--;
cout<<s[top]<<" ";
s[++top]=t;
}
return 0;
}
-
在基于链表的算法中,无用数据并没有被删除,我们是通过了一个前跳指针指向前方第 1 个比自己大的数。因为数据没有删掉,所以,找数据的时候就是"跳,跳,跳",跳过了无用的数据。
-
在现在学的新算法当中,无用数据被清理删除,留下来的数据都是有用(或者说,不能排除它有用)。删完的数据一般没剩多少,在查找的时候可以按顺序来查(数据量大的时候,还可以进一步叠加二分查抄算法)。
所以,两种算法的一些精髓是一样的,但是在细节上走了不同的路线。下面,我们见一下这个新算法的操作步骤。
-
这个算法叫 单调栈。栈的特点是先入后出,这和队列的特性先入先入相反。但是,作为小朋友我们先不要太关注这些理论性的东西(除非你很聪明,思路非常非常清晰),我们就只管使用就好了。在上面的例子中,我们总是试图扔掉尾巴部分的一些没用的东西,扔掉东西的过程叫出栈,最后把新来的数字加到尾巴那里去教入栈,有没有留意到,这个算法里面并没有从队头去取数据。上面这些图像里,留下来的数据总是呈现出单调性,这一题,就是单调递减栈,删除无用数据之后,剩下来的柱子是从左到右越来越矮的,类似,还有单调递增栈,思想是一样的。(除了单调栈之外,的确还有单调队列,我们会在其它题目中讲述)。
-
删垃圾数据的过程就是出栈了,可以用 STL 的 stack 模板,自己写个数组来实现也可以。
-
详细步骤是:
-
来了新数据之后,先检查栈尾部有没有垃圾数据,如果有就删除(出栈)
-
删除完之后,如果栈已经空了,就表示没有符合要求的数(查找失败),如果有,就输出栈顶数据
-
把新来的数据入栈
-
我这里是用了栈的思想和数组做的。