C++ stack 栈
头文件:
#include<stack>栈:后进先出 LIFO,后压入栈的元素,最先拿出来。
常用成员汇总
| 函数 | 作用 |
|---|---|
st.push(x) |
将x压入栈顶 |
st.top() |
获取栈顶元素,不删除 |
st.pop() |
删除栈顶,void无返回 |
st.empty() |
栈空返回true |
st.size() |
返回栈中元素数量 |
注意:栈不能遍历,不能随机访问sti,只能操作栈顶。
2.可以存什么类型
cpp
stack<int> st1;
stack<pair<int,int>> st2;
stack<string> st3;
//pair入栈
st2.push({1,2});
auto p = st2.top();
st2.pop();
3.栈使用场景
- ** 括号匹配**(经典)
. P1739 表达式括号匹配 - 洛谷
**32. 最长有效括号 - 力扣(LeetCode)**
2.模拟进出栈
4.栈的例题
#include <iostream>
#include <stack>
using namespace std;
int main() {
stack<char> st;
char c;
while (cin >> c) {
if (c == '#') break;
if (c == '(') {
st.push(c);
} else if (c == ')') {
if (st.empty()) {
cout << "NO" << endl;
return 0;
}
st.pop();
}
}
if (st.empty()) {
cout << "YES" << endl;
} else {
cout << "NO" << endl;
}
return 0;
}
题目:判断括号是否匹配。
思路:
遇到左括号 '(' 入栈;
遇到右括号 ')':
- 如果栈为空,直接不匹配;
- 否则弹出栈顶(抵消一对括号)。
遍历结束,栈必须为空才算全部匹配。
cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
string s;
cin>>s;
stack<char> st;
bool ok=true;
for(auto ch:s){
if(ch=='('){
st.push(ch);
}else if(ch==')'){
if(st.empty()){
ok=false;
break;
}
st.pop();
}
}
if(ok && st.empty()) cout<<"YES";
else cout<<"NO";
return 0;
}
题目大意:可以匹配的括号中,所有括号共有多少
思路:遇到左括号,把他的下标进栈,遇到右括号,弹出栈顶,()))像这种尽管前面有2个有效括号,但有个右括号后就不匹配了,更改新的有效长度起点,一直出现右括号,就会进入栈空条件,让当前下标进入栈里,也就更新了有效括号的起始位置,栈里首先要要进一个数字-1,)()或())像这种防止栈里没有左括号时栈空(((()像这种一直出现左括号,栈顶会是出现有效括号最后一次左括号的位置
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s;
cin>>s;
stack<int>st;
st.push(-1);
int max1=0;
for(int i=0;i<s.size();i++)
{
if(s[i]=='(')
st.push(i);
else
{
st.pop();
//不再有效 ,招到新的栈顶元素
if(st.empty())
st.push(i);
//在每段有效中找到最长的那段
else
max1=max(max1,i-st.top());
}
}
cout<<max1<<endl;
}
题目大意:oo==O,OO=空,按照这个规则把字符串压缩
思路:栈空时直接把此元素入栈,并且退出循环,遍历下一个字符,遇到oo时,变为O后要循环有没有和O能消的,遇到OO时,消完后退出此次循环,读取下一个字符,不是这两种情况的,记录当前字符退出循环,读取下一个字符
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define pii pair<int,int>
#define fi first
#define se second
const int N=101;
void slove(){
string s;
cin>>s;
stack<char>st;
for(auto c:s){
char now = c;
// 必须while循环,如果为空的话,只会把当前字符入栈,
//不能产生两种字符对比,要退出循环
while(true)
{
if(st.empty()){
st.push(now);
break;
}
char tp = st.top();
//这里还要进行循环,这里结合成的O可能会和前面O抵消
//或者栈空把·O入栈
//或者o,把O入栈
if(tp == 'o' && now == 'o')
{
st.pop();
now = 'O';
}
//每次进入一个字符时,都会进行oo,OO这样的结合
//再不能进行这两种的结合后,就是进入下面两个条件之一
//退出循环,读入下一个字符
else if(tp == 'O' && now == 'O')
{
st.pop();
break;//进行到这,之前能结合的都结合过了,退出去就行
}
//
else
{
st.push(now);//没有可结合的
break;
}
}
}
string s1;
while(!st.empty()){
s1.push_back(st.top());
st.pop();
}
reverse(s1.begin(),s1.end());
cout<<s1<<endl;
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int _;
cin>>_;
while(_--)
slove();
return 0;
}
题目大意:模拟这列数字能不能按照给出的出栈方式出栈
思路:当进栈的那个元素与给出的序列前端的那个元素相等时,弹出栈顶,让下一个字符与栈顶元素比较
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define pii pair<int,int>
#define fi first
#define se second
//把一组从1-n的数字按照入栈和出栈的性质,看能否操作出出栈后是给出的这段序列,
//5 4 1 2 3,5个数字全部入栈了,5 4 弹出后,还没弹出 3 2就先弹出1了
//3 2 1 4 5
//3 2 4 1 5
//5 4 3 2 1
void slove(){
int n;
while(cin >> n && n != 0) // 读到n=0整体结束
{
int target;
while(cin >> target)
{
if(target == 0) break; // 当前n的所有查询结束
vector<int> seq;
seq.push_back(target);
// 读取本行剩余数字
for(int i=2;i<=n;i++)
{
cin >> target;
seq.push_back(target);
}
stack<int> st;
int now = 1; // 下一个要进站的车厢
bool ok = true;
for(int x : seq)
{
// 不断入栈直到栈顶等于x
//再入栈的元素不是栈顶或栈空时,这些元素都进栈
while(now <= n && (st.empty() || st.top() != x))
{
st.push(now++);
}
//这个数字也要出栈的一样,去掉栈顶,等到下一次循环
//要出栈的元素X可能就是新的栈顶,如果不出栈,就会进入while进栈
if(st.top() == x)
{
st.pop();
}
else
{
ok = false;
break;
}
}
if(ok) cout << "Yes" << endl;
else cout << "No" << endl;
}
cout << endl; // 每组n处理完输出空行,题目要求
}
}
signed main(){
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
slove();
return 0;
}