对顶栈and双端队列

对顶栈-引入

小可写文章

题目描述

小可的文艺气息非常浓重,平时的他总喜欢写一些文章。但是苦于没有一个合适的编辑器。

现在小可打算自己动手制作一个文本编辑器用来高效的看文章和写文章。

编辑器是运行在Linux命令行下的,因此只能通过指定的指令进行操作。指令如下:

Insert X,在当前光标位置插入字符串x
Del,删除光标前的一个字符串
Left,光标向左移动一下
Right,光标向右移动一下
输入描述

第一行一个整数N,表示有N个操作。

然后输入N行,表示N个操作。

输出描述

输出包含两行

第一行为光标之前的内容

第二行为光标之后的内容

输入样例

3 Insert Coduck Left Insert Hello
输出样例

Hello Coduck
数据范围

30%的数据下:N不超过1000

100%的数据下:N不超过100000

数据保证文章中每个字符串长度不超过100

冷静分析:光看插入和删除操作,用一个栈进行push pop是很容易的
可是,这个光标左移右移着实烦人 怎么办呢? 细想一下,光标左半边是一部分,光标右半边是一部分,这不就两个栈吗? 但又有疑问,光标的每次操作总不能重新维护两个栈吧
你只需要把两个栈之间的元素弹来弹去来模拟光标移动

看代码细品一下~~

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<stack>
using namespace std;
int n;
string com, s;
stack<string> q1, q2, q3;
int main() {
	scanf("%d", &n);
	while (n--) {
		cin >> com;
		if (com == "Insert") {
			cin >> s;
			q1.push(s);
		} else if (com == "Left") {
			if (!q1.empty()) {
				q2.push(q1.top());
				q1.pop();
			}
		} else if (com == "Right") {
			if (!q2.empty()) {
				q1.push(q2.top());
				q2.pop();
			}
		} else{
			if (!q1.empty()) q1.pop();
		}
	}
	while (!q1.empty()) {
		q3.push(q1.top());
		q1.pop();
	}
	while (!q3.empty()) {
		cout << q3.top() << " ";
		q3.pop();
	}
	printf("\n");
	while (!q2.empty()) {
		cout << q2.top() << " ";
		q2.pop();
	}
	return 0;
}

tip:注意Left和Right首字母大写!!!

进阶版

功能强大编辑器

你要帮助小可创造一个超级数字编辑器!编辑器依旧运行在Linux下,因此你只能通过指令去操控他。指令有五种:
In X表示在光标左侧插入一个数字
Del 表示删除光标左侧一个数字
Left 表示光标向左移动一下
Right 表示光标向右移动一下
Ask k表示光标之前的序列为 a ​1 ​​ ,a ​2 ​​ ,a ​3 ​​ … a ​k ​​ ,输出前面序列最大的子序列和
输入描述

输入第一行包含一个整数Q,表示指令数量。

然后输入Q行,表示Q个指令。

输出描述

对于每个Ask k均输出一行,表示询问结果。

输入样例

8 In 2 In -1 In 1 Ask 3 Left Del Right Ask 2
输出样例
2 3
数据范围
50%的数据,Q不超过1000.
100%的数据,Q不超过1000000,且x不超过1000

此题作为思考题,其实就是上面代码改改加个前缀和

双端队列&&单调队列

#include<deque>

额,就是比STL容器中正常队列入队出队多个前后之分 push_front() push_back()
pop同理,其实没啥太大变化,具体看例题代码

滑动最小值

有一个序列,共有n个数字,请你求出以每个数字开始的长度为k的区间中的最小值。

输入描述

多组测试数据,输入0 0表示结束。

第一行包含两个整数,n和k。
然后输入n个正整数。
输出描述

输出题面描述的答案,如果i>n-k,则无法查找到最小值,不进行输出。

输入样例

5 2 1 2 3 4 5 0 0
输出样例

1 2 3 4
数据范围

30%的数据:n<1000

100%的数据,n<1000000

                        
#include<iostream>
#include<algorithm>
#include<deque>
#include<cstring>
using namespace std;
const int N=1e6+10;
int n,k,a[N];
deque<int> q;
int main(){
	while(scanf("%d%d",&n,&k)&&n&&k){
		memset(a,0,sizeof a);
		for(int i=1;i<=n;++i) scanf("%d",&a[i]);
		for(int i=1;i<=n;++i){
			if(i>k){//如果当前位置大于k说明前k个数一定找到最小值,直接输出,想都不想 
				cout<<q.front()<<" ";
				if(q.size()>=1&&q.front()==a[i-k]) q.pop_front();//区间长度为k,a[i-k]就是不在区间里的左边第一个数
			}//队列里如果存在这样的数,就踢出去,因为这样的数肯定不在当前的区间里,根本不可能提供答案 
			while(!q.empty()&&q.back()>a[i]) q.pop_back();//维护一个单调递增队列 
			q.push_back(a[i]);
		}
		cout<<q.front()<<"\n";
		q.clear();//多组输入别忘把队列清空 
	} 
	return 0;
}

解析就在代码中,结合代码仔细想一想~~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值