栈
描述:后进先出
实现:可以用链表,数组
应用
A:括号匹配验证
实现:
对于左括号进栈,对于右括号判断栈是否为空,若为空,则匹配失败,否则出栈。
对于只用一种括号的情况:有另一种改进方式,其实可用一个计数变量,初始化为0,直接统计左单括号即可,不用存储括号类型。
B:进制转换
C:算术表达式的计算
用两个栈:一个存储符号,一个存储数值
D:递归的应用,保存断点
E:深度优先搜索
F:单调栈
题目描述:给定一个连续的不同高度的矩形,求能合并的最大矩形面积点击打开poj题目链接
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define N 100010
using namespace std;
struct Node
{
int id;
int num;
}s[N];
struct ST
{
int b;
int e;
int sum;
}c[N];
long long a[N];
int main()
{
//freopen("in.txt","r",stdin);
int n;
while( scanf("%d",&n),n )
{
for( int i=1; i<=n; i++ )
{
scanf("%lld",&a[i]);
}
int top=0,j;
s[0].num=0;s[0].id=0;
for( int i=1; i<=n; i++ )
{
for(j=top; j>=0; j-- )
{
if( a[i]>s[j].num) break;
else
{
c[s[j].id].e=i-1;
}
}
s[j+1].id=i;s[j+1].num=a[i];
top=j+1;c[i].b=s[top-1].id+1;
}
for( int i=0; i<=top; i++ ) c[s[i].id].e=n;
long long ans=0;
for( int i=1; i<=n; i++ )
{
long long sum=(c[i].e-c[i].b+1)*a[i];
if( sum>ans ) ans=sum;
}
cout<<ans<<endl;
}
return 0;
}
给定输入顺序为1~N..可用一个栈操作判断能否得到给定的输出顺序点击打开poj题目链接
#include <iostream>
#include <cstdio>
#include <cstring>
#define N 1010
using namespace std;
int main()
{
//freopen("in.txt","r",stdin);
int a[N],b[N],n;
while( scanf("%d",&n),n )
{
while( scanf("%d",&a[0]))
{
bool flag=true;
if( a[0]==0 ) break;
for( int i=1; i<n; i++ )
scanf("%d",&a[i]);
int i=1,j=0,top=0;
while( i<=n )
{
if( i!=a[j] )
{
b[top++]=i;i++;
}
else j++,i++;
while( top>0&&j<n&&b[top-1]==a[j] ) j++,top--;
//i++;
}
if( top>0 ) printf("No\n");
else printf("Yes\n");
}
printf("\n");
}
return 0;
}
队列
描述:先进先出,正由于这个思想,经常用来做缓冲
实现:数组,链表
A: 顾名思义,用来排队。比如舞伴配对问题
假设在周末舞会上,男士们和女士们进入舞厅时,各自排成一队。跳舞开始时,依次从男队和女队的队头上各处一人配成舞伴。若两队初始人数不相同,则较长的那一对中未配对者等待下一轮舞曲。请模拟上述舞伴配对问题。
B:缓冲队列,用于操作系统中进程调度缓冲
C:优先级队列 ,用堆实现,根据优先级进行进程调度
D:用于广度优先搜索,比如迷宫问题点击打开poj题目链接
给定n,k,求最少通过多少次 n+1,n-1 ,n*2 操作使得n==k点击打开poj题目链接
#include<iostream>
#include<cstring>
#define N 200003
using namespace std;
typedef struct {
int x;
int step;
}Node;
Node queue[N];
int mark[N],a,b;
int bfs(){
Node temp;
memset(mark,0,sizeof(mark));
int front,rear,i,j;
front=rear=0;
queue[rear].x=a;
queue[rear++].step=0;
while(front<rear){
temp=queue[front++];
if(temp.x==b){
return temp.step;
}
if((temp.x-1)<N&&!mark[temp.x-1]){
mark[temp.x-1]=1;
queue[rear].x=temp.x-1;
queue[rear++].step=temp.step+1;
}
if((temp.x+1)<N&&!mark[temp.x+1]){
mark[temp.x+1]=1;
queue[rear].x=temp.x+1;
queue[rear++].step=temp.step+1;
}
if((temp.x*2)<N&&!mark[temp.x*2]){
mark[temp.x*2]=1;
queue[rear].x=temp.x*2;
queue[rear++].step=temp.step+1;
}
}
return -1;
}
int main(){
cin>>a>>b;
cout<<bfs()<<endl;
}
E:循环队列
F:双端队列,队头和对尾都可进可出
G:单调队列,队列元素保持单调性的队列
给定n个数,从左到右每次选取m个数,求这m个数中的最大值和最小值。点击打开poj题目链接
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#define INF ~0u>>1
#define OO -0x7fffffff
#define N 1000010
using namespace std;
int a[N], q[N], d[N];
int main()
{
int n ,k;
while( scanf("%d%d",&n,&k)!=EOF )
{
for( int i = 0; i < n; i ++ ){
scanf("%d",&a[i]);
}
int front = 0, rear = 0;
d[rear] = 0;
q[rear++] = a[0]+1;
for( int i = 0; i < n; i ++ )
{
while ( a[i] < q[rear-1] && rear>front ) rear --;
d[rear] = i;
q[rear++] = a[i];
if( i>=k-1 )
{
if( n != i+1 ) printf("%d ",q[front]);
else printf("%d\n",q[front]);
if( d[front] == i-k+1 ) front++;
}
}
front = rear = 0;
d[rear] = 0;
q[rear++] = a[0]-1;
for( int i = 0; i < n; i ++ )
{
while ( a[i] > q[rear-1] && rear>front ) rear --;
d[rear] = i;
q[rear++] = a[i];
if( i>=k-1 )
{
if( n != i+1 ) printf("%d ",q[front]);
else printf("%d\n",q[front]);
if( d[front] == i-k+1 ) front++;
}
}
}
return 0;
}