一. (1047.) 删除字符串中的所有相邻重复项

算法原理:
关键点是当前元素是否被消除,需要知道上一个元素的信息。完美符合栈的特性,后进先出,后入栈的元素和栈顶元素相比较,等于就使栈顶元素出栈,不等于就自己进栈,但本题要求返回string,用栈得到结果后还要转化为string,可以直接用数组来模拟栈,在数组的尾部进行尾插尾删,实现栈的进栈和出栈
cpp
class Solution {
public:
string removeDuplicates(string s) {
string ret;//用数组模拟栈
for(auto c:s)
{//注意字符串为空时会非法访问
if(ret.size()&&c==ret.back()) ret.pop_back();//模拟出栈
else ret+=c;//模拟入栈
}
return ret;
}
};
二. (844.) 比较含退格的字符串

算法原理:
由于退格的时候需要知道前⾯元素的信息,⽽且退格也符合后进先出的特性。因此我们可以使⽤「栈」结构来模拟退格的过程。与上题思路相同
当遇到⾮ # 字符的时候,直接进栈;
当遇到 # 的时候,栈顶元素出栈
cpp
class Solution {
public:
bool backspaceCompare(string s, string t) {
string ret1,ret2;
for(auto c:s)
{
if(ret1.size()&&c=='#') ret1.pop_back();//字符串为空时不需要退格
if(c!='#') ret1+=c;//结果中部包含退格
}
for(auto c:t)
{
if(ret2.size()&&c=='#') ret2.pop_back();
if(c!='#') ret2+=c;
}
if(ret1==ret2) return true;
else return false;
}
};
三. (227.) 基本计算器 II

算法原理:
本题表达式中没有括号,只用处理加减乘除混合运算即可,先乘除后加减。分情况讨论,表达式中字符只有三种情况,分别为空格、运算符和数字,数字注意要提取链接起来,因为有可能是多位数的运算。可以先设置一个变量记为'+',每遇到运算符就更新。用数组模拟的栈中存储元素,遇到乘除就及时计算,减号就转化为负数入栈,最终就可以不用考虑每个数之间的加减关系,全部相加即为结果。
除此之外还有两栈处理和逆波兰表达式的思路
cpp
class Solution {
public:
int calculate(string s) {
vector<int> st;//用数组模拟栈
char c='+';//保存每一个数的前一个符号
int i=0;
while(i<s.size())
{
//分三种情况讨论
if(s[i]==' ') i++;//1.为空格时
else if(s[i]>='0'&&s[i]<='9')//2.为数字时
{
//提取数字
int tmp=0;//每次循环前tmp必须重置,因为tmp值涉及前一值和当前值
while(i<s.size()&&s[i]>='0'&&s[i]<='9') tmp=(tmp*10+(s[i++]-'0'));
if(c=='+') st.push_back(tmp);
else if(c=='-') st.push_back(-tmp);
else if(c=='*') st.back()*=tmp;
else st.back()/=tmp;
}
else{//3.为运算符时
c=s[i++];
}
}
//同一加法处理返回值
int ret=0;
for(auto n:st) ret+=n;
return ret;
}
};
四. (394.) 字符串解码

算法原理:
注意:
1.用双栈来实现,每次遇到']'时拿出字符栈顶元素(记为m)和数字字符栈顶元素(记为n),让m拼接n次,pop掉字符和数字栈原来的栈顶元素,push到新的栈顶元素后
2.当遍历到左右括号时要跳过括号进行提取操作
3.提取字符串与提取数字的操作相同
其余细节见代码
cpp
class Solution {
public:
string decodeString(string s) {
stack<int> nums;
stack<string> st;
st.push("");//防止越界
int i=0,n=s.size();//遍历s的下标
while(i<n)
{
//提取数字并入栈
if(s[i]>='0'&&s[i]<='9')
{
int tmp=0;
while(i<n&&s[i]>='0'&&s[i]<='9') tmp=tmp*10+(s[i++]-'0');
nums.push(tmp);
}
//遇到'[',提取字符入栈
else if(s[i]=='[')
{
i++;//跳过括号
string str;
while(i<n&&s[i]>='a'&&s[i]<='z') str+=s[i++];
st.push(str);
}
//判断括号,右括号第一次出现
else if(s[i]==']'){
string str=st.top();//拼接重复字符串
int k=nums.top();
nums.pop();//用完数字和字符栈顶元素后要删除
st.pop();
while(k--)
{ //将拼接后字符串放入上一个栈元素后面
st.top()+=str;
}
i++;//跳过右括号
}
//遇到单独的字符,提取出来放到st栈顶元素后
else while(i<n&&s[i]>='a'&&s[i]<='z') st.top()+=s[i++];
}
return st.top();
}
};
五. (946. 验证栈序列)

算法思路:
⽤栈来模拟进出栈的流程。
⼀直让元素进栈,进栈的同时判断是否需要出栈。当所有元素模拟完毕之后,如果栈中还有元素,那么就是⼀个⾮法的序列。否则,就是⼀个合法的序列。或者用出栈的指针判断是否遍历完数组,完则正确,反之
cpp
class Solution {
public:
bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
vector<int> st;//模拟栈
int i=0;//弹出数组指针
for(auto n:pushed)
{
st.push_back(n);
while(i<popped.size()&&!st.empty()&&st.back()==popped[i]) st.pop_back(),i++;
//else st.push_back(n);
}
if(st.empty()) return true;
else return false;
}
};