文章目录
栈
栈 计蒜客 - A1047
问题描述
这是一个简单的栈问题,你将会有4个操作:
- push x 将 x 入栈;
- pop 将栈顶元素移除;
- sum 是输出此时栈里的元素的个数;
- out 是将栈的元素全部输出。
输入格式:
本题多组测试数据,每组第一行输入一个整数 n (n<100),代表接下来的操作数。
接下来的 n 行输入操作方式。
输出格式:按题意输出,并换行。
样例输入
7
push 12
push 142
push 456
sum
pop
sum
out
样例输出
3
2
142
12
- 参考程序
#include<iostream>
#include<string>
#include<cstring>
using namespace std;
const int N=1e5+10;
int sta[N], head=0;
void push(int x) {//入栈
sta[++head] = x;//[1,N]
}
void pop() {//出栈
--head;
}
int top() {//栈顶
return sta[head];
}
bool empty() {//栈空
return head==0;
}
int size() {
return head;
}
void out() {
for(int i=head; i>=1; i--) {
cout<<sta[i]<<endl;
}
}
void init() {
//memset(sta,0,sizeof(sta));
head=0;
}
int main() {
//freopen("data.in","r",stdin);
int n;
while(cin>>n) {
init();
for(int i=1; i<=n; i++) {
string op; int x; cin>>op;
if(op=="push") {
cin>>x; push(x);
} else if(op=="sum") {
cout<<size()<<endl;
} else if(op=="pop") {
pop();
} else if(op=="out") {
out();
}
}
}
return 0;
}
操作栈 51Nod - 3199
问题描述
有一个初始为空的栈,我们对这个栈进行n次操作,操作共分为2种:
- 1 x(将数字 x 放入栈)
- 2(将栈顶元素弹出)
对于第2种操作,你需要把弹出的这个数字输出,如果进行操作2时,栈为空,则输出"empty"。
例如:n = 5,对应的操作为:
1 123 (操作后栈里面的元素为:123)
1 234(操作后栈里面的元素为:123, 234)
2(输出:234,操作后栈里面的元素为:123)
2(输出:123,操作后栈里面的元素为:空)
2(输出:empty)
对应后面3个第2类操作,你的程序需要输出,
234
123
empty
输入格式:第一行,1个数n(1 <= n <= 10000);
后面n行,每行1种操作,1 X或者2(0 <= x <= 10000)。
输出格式:对应所有操作2,输出被弹出的数或者"empty"
样例输入
5
1 123
1 234
2
2
2
样例输出
234
123
empty
- 参考程序
#include<iostream>
#include<stack>
using namespace std;
stack<int> sta; // 定义格式
int main(){
// freopen("data.in", "r", stdin);// read
// freopen("data.out", "w", stdout);// write
int n; cin>>n;
for(int i=1; i<=n; i++){
int op,x; cin>>op;
if(op==1){
cin>>x; sta.push(x);
}else if(op==2){
if(sta.empty()) {
cout<<"empty"<<endl;
}else {
cout<<sta.top()<<endl;
sta.pop();
}
}
}
return 0;
}
出栈合法性 计蒜客 - T1565
问题描述
已知自然数 1, 2, …, N(1≤N≤100)依次入栈,请问序列 C1,C2,…,CN是否为合法的出栈序列。
输入格式
输入包含多组测试数据。
每组测试数据的第一行为整数 N(1≤N≤100),当 N=0 时,输入结束。
第二行为 N 个正整数,以空格隔开,为出栈序列。
输出格式
对于每组输入,输出结果为一行字符串。
如给出的序列是合法的出栈序列,则输出"Yes",否则输出"No"。
样例输入
5
3 4 2 1 5
5
3 5 1 4 2
0
样例输出
Yes
No
- 参考程序
#include<iostream>
#include<algorithm>
using namespace std;
const int N=110;
int a[N], sta[N],head=0,pre=0;
int main(){
//freopen("data.in","r",stdin);
int n;
while(cin>>n){
if(n==0) break;
for(int i=1;i<=n;i++) cin>>a[i];
head=0,pre=1;
for(int i=1;i<=n;i++){
pre=max(pre,a[i-1]+1);//原本应该出现的元素
if(a[i]>pre){//升序入栈
for(int j=pre;j<a[i];j++){
sta[++head]=j;
}
}else if(a[i]==sta[head]){
--head;
}
}
if(head>0) cout<<"No\n";
else cout<< "Yes\n";
}
return 0;
}
表达式括号匹配 计蒜客 - T1655
问题描述
给出一个表达式,该表达式仅由字符(、)、+、-以及数字组成。
请编写一个程序检查表达式中的左右圆括号是否匹配,若匹配,则返回"YES";否则返回"NO"。
输入格式:一行一个表达式,长度不超过 2000。
输出格式:若匹配,则输出"YES";否则输出"NO"
样例输入:2+(3-4)-2-6)
样例输出:NO
- 参考程序
#include<iostream>
#include<algorithm>
#include<stack>
using namespace std;
stack<char> sta;
int main(){
// freopen("data.in","r",stdin);
string s; getline(cin, s);
bool flag=1;
for(int i=0; i<s.length(); i++){
if(s[i]=='(') sta.push(s[i]);
else if(s[i]==')') {
if(!sta.empty()) sta.pop();
else {
flag=0; break;
}
}
}
if(flag && sta.empty()) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
return 0;
}
括号匹配 计蒜客 - 42574
问题描述
蒜头君在纸上写了一个串,只包含’(‘和’)‘。
一个’(‘能唯一匹配一个’)‘,但是一个匹配的’(‘必须出现在’)'之前。
请判断蒜头君写的字符串能否括号完全匹配,
如果能,输出配对的括号的位置(匹配的括号不可以交叉,只能嵌套)。
输入格式
一行输入一个字符串只含有’(‘和’)',输入的字符串长度不大于 50000。
输出格式
如果输入括号不能匹配,输出一行"No",否则输出一行"Yes",
接下里若干行每行输出 2 个整数,用空格隔开,表示所有匹配对的括号的位置(下标从 1 开始)。
你可以按照任意顺序输出。
样例输入
(())
样例输出
Yes
1 4
2 3
- 参考程序
#include<iostream>
#include<algorithm>
#include<stack>
#include<string>
using namespace std;
const int N=1e5+10;
int a[N], b[N], cnt=0;
stack<int> sta;
int main(){
// freopen("data.in","r",stdin);
string s; getline(cin, s);
bool flag=1;
for(int i=0; i<s.length(); i++){
if(s[i]=='(') sta.push(i);
else if(s[i]==')') {
if(!sta.empty()) {
++cnt;
a[cnt] = sta.top()+1;
b[cnt] = i+1;
sta.pop();
} else {
flag=0; break;
}
}
}
if(flag && sta.empty()) {
cout<<"Yes"<<endl;
for(int i=1; i<=s.length()/2; i++){
cout<<a[i]<<" "<<b[i]<<endl;
}
}else cout<<"No"<<endl;
return 0;
}
后缀表达式(逆波兰表达式) 51Nod - 3404
问题描述
后缀表达式是一种把运算符后置的算术表达式,例如普通的表达式 2 + 3 的后缀表示法为 2 3 +。
后缀表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如 (2 + 3) * 4 的后缀表示法为 2 3 + 4 *。
本题求解后缀表达式的值,其中运算符包括+ - * /四个。
计算后缀表达式,要从前向后遍历字符串。
当遇见运算数时,压入栈中。
当读到运算符时,将栈中的连续2个运算数弹栈;
用当前运算符计算后(注意后缀表达式的先出栈的运算数,放在运算符后面;后出栈的运算数,放在运算符前面),再将结果压栈。
最后的栈顶就是后缀表达式的运算结果。
输入格式:输入为一行,其中运算符和运算数之间都用空格分隔,运算数是浮点数。
输出格式:输出为一行,表达式的值。
输入样例:11.0 12.0 + 24.0 35.0 + *
输出样例:1357.000000
可使用以下语句保留固定长度的小数点后尾数
C++:cout<<setiosflags(ios::fixed)<<setprecision(6)<<ans<<endl;
C:printf("%.6lf\n", ans);
- 参考程序
#include<iostream>
#include<stack>
#include<cstring>
#include<cstdlib>
#include<cstdio>
using namespace std;
stack<double> sta;
double n,m;
char s[110];
int main(){
// freopen("data.in", "r", stdin);
while(~scanf("%s", s)){
if(s[0]!='+' && s[0]!='-' && s[0]!='*' && s[0]!='/' ){
sta.push(atof(s));//字符数组转数字的 2种方式
// sscanf(s, "%lf", &n); sta.push(n);
}else if(strlen(s)>1){//负数的情况
sta.push(atof(s));
}else{
n = sta.top(); sta.pop();
m = sta.top(); sta.pop();
switch(s[0]){
case '+': sta.push(m+n); break;
case '-': sta.push(m-n); break;
case '*': sta.push(m*n); break;
case '/': sta.push(m/n); break;
}
}
}
printf("%.6lf\n", sta.top());
return 0;
}
中缀表达式求值 51Nod - 3425
问题描述
现在给你一个中缀表达式,式子中包括±*/()六种运算符号,要求你求出这个中缀表达式的值。
中缀表达式:所谓中缀表达式就是我们平常写的算式,例如1+2、(1+2)*3,。
输入格式:输入一个中缀表达式。
输出格式:输出一行,表示表达式的值。
输入样例:( 11.0 + 12.0 ) * ( 24.0 + 35.0 )
输出样例:1357.000000
- 参考程序
波兰表达式 OpenJ_Bailian - 2694
问题描述
波兰表达式是一种把运算符前置的算术表达式,
例如普通的表达式2 + 3的波兰表示法为+ 2 3。
波兰表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,
例如(2 + 3) * 4的波兰表示法为* + 2 3 4。
本题求解波兰表达式的值,其中运算符包括+ - * /四个。
输入格式:输入为一行,其中运算符和运算数之间都用空格分隔,运算数是浮点数。
输出格式:输出为一行,表达式的值。可直接用printf(“%f\n”, v)输出表达式的值v。
样例输入:* + 11.0 12.0 + 24.0 35.0
样例输出:1357.000000
提示
可使用 atof(str) 把字符串转换为一个 double 类型的浮点数。
atof 定义在 math.h 中。
此题可使用函数递归调用的方法求解。
- 参考程序
#include<iostream>
#include<stack>
#include<cstdio>
#include<cstdlib>
using namespace std;
double fun(){
char s[110]; scanf("%s", s);
switch(s[0]){
case '+': return fun()+fun();
case '-': return fun()-fun();
case '*': return fun()*fun();
case '/': return fun()/fun();
}
return atof(s);
}
int main(){
printf("%lf\n", fun());
return 0;
}
简单计算器 HDU - 1237
问题描述
读入一个只包含 +, -, *, / 的非负整数计算表达式,计算该表达式的值。
输入格式
测试输入包含若干测试用例,每个测试用例占一行,每行不超过200个字符,
整数和运算符之间用一个空格分隔。
没有非法表达式。
当一行中只有0时输入结束,相应的结果不要输出。
输出格式
对每个测试用例输出1行,即该表达式的值,精确到小数点后2位。
输入样例
1 + 2
4 + 2 * 5 - 7 / 11
0
输出样例
3.00
13.36
- 参考程序
#include<iostream>
#include<iomanip>
#include<stack>
#include<cstdio>
using namespace std;
int main() {
// freopen("data.in", "r", stdin);
double a,b,c; char ch;
while(cin>>a){
stack<double> sta;
sta.push(a);
while(getchar()!='\n'){//空格
cin>>ch>>b;
if(ch=='+') sta.push(b);
else if(ch=='-') sta.push(-b);
else if(ch=='*') {
c = sta.top(); sta.pop();
sta.push(b*c);
}else if(ch=='/'){
c = sta.top(); sta.pop();
sta.push(c/b);
}
}
if(sta.size()==1 && sta.top()==0) return 0;
double ans=0;
while(!sta.empty()){
ans += sta.top(); sta.pop();
}
cout<<fixed<<setprecision(2)<<ans<<endl;
}
return 0;
}
出栈序列统计 OpenJ_Bailian - 4077
问题描述
栈是常用的一种数据结构,有n个元素在栈顶端一侧等待进栈,栈顶端另一侧是出栈序列。
你已经知道栈的操作有两种:push和pop,前者是将一个元素进栈,后者是将栈顶元素弹出。
现在要使用这两种操作,由一个操作序列可以得到一系列的输出序列。
请你编程求出对于给定的n,计算并输出由操作数序列1,2,…,n,经过一系列操作可能得到的输出序列总数。
输入格式:就一个数n(1≤n≤15)。
输出格式:一个数,即可能输出序列的总数目。
输入样例:3
输出样例:5
提示
先了解栈的两种基本操作,进栈push就是将元素放入栈顶,栈顶指针上移一位,
等待进栈队列也上移一位,出栈pop是将栈顶元素弹出,同时栈顶指针下移一位。
用一个过程采模拟进出栈的过程,可以通过循环加递归来实现回溯:
重复这样的过程,如果可以进栈则进一个元素,如果可以出栈则出一个元素。
就这样一个一个地试探下去,当出栈元素个数达到n时就计数一次(这也是递归调用结束的条件)。
- 参考程序
#include<iostream>
#include<queue>
using namespace std;
//未入栈元素个数,栈内元素个数
int dfs(int a,int b){
if(a==0 && b==0) return 1;
else if(a>0 && b>0) return dfs(a-1, b+1)+dfs(a, b-1);
else if(a>0 && b==0) return dfs(a-1, b+1);
else if(a==0) return dfs(a, b-1);
}
int main() {
// freopen("data.in", "r", stdin);
int n; cin>>n;
cout<<dfs(n,0)<<endl;
return 0;
}
P4387 【深基15.习9】验证栈序列
题目描述
给出两个序列 pushed 和 poped 两个序列,其取值从 1 到 n(n≤100000)。
已知入栈序列是 pushed,如果出栈序列有可能是 poped,则输出 Yes,否则输出 No。
为了防止骗分,每个测试点有多组数据。
输入格式
第一行一个整数 q,询问次数。
接下来 q 个询问,对于每个询问:
第一行一个整数 n 表示序列长度;
第二行 n 个整数表示入栈序列;
第三行 n 个整数表示出栈序列;
输出格式
对于每个询问输出答案。
输入样例
2
5
1 2 3 4 5
5 4 3 2 1
4
1 2 3 4
2 4 1 3
输出样例
Yes
No
- 参考程序
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int q,n;
int pushed[N],poped[N];
stack<int> sta;
//根据入栈序列,判断出栈序列是否合法
bool islegal(){
while(!sta.empty()) sta.pop();//栈的清空
int pre=0;
for(int i=0; i<n; i++){
sta.push(pushed[i]);
while(!sta.empty() && sta.top()==poped[pre]){
sta.pop(); pre++;
}
}
if(sta.empty()) return 1;
return 0;
}
int main(){
// freopen("data.in", "r", stdin);
scanf("%d", &q);
while(q--){
scanf("%d", &n);
for(int i=0; i<n; i++) scanf("%d", &pushed[i]);
for(int i=0; i<n; i++) scanf("%d", &poped[i]);
printf("%s\n", islegal() ? "Yes" : "No");
}
return 0;
}