
上篇我们介绍了栈算法的基本原理和应用,本题将结合进阶题目进行讲解。进一步深化对于栈算法的理解运用。
由于退格的时候需要知道「前⾯元素」的信息,⽽且退格也符合「后进先出」的特性。因此我们可以使⽤「栈」结构来模拟退格的过程。 • 当遇到⾮ # 字符的时候,直接进栈; • 当遇到 # 的时候,栈顶元素出栈。
为了⽅便统计结果,我们使⽤「数组」来模拟实现栈结构
class Solution {
public:
string change(string& r)
{
int n=r.size();
string ret="";
for(auto ch:r)
{
if(ch=='#')
{
if(ret.size())
{
ret.pop_back();
}
}//回退操作,如果ret元素为空则无需删除
else
{
ret+=ch;
}
}
return ret;
}
bool backspaceCompare(string s, string t) {
s=change(s);
t=change(t);
return s==t;
}
};由于表达式⾥⾯没有括号,因此我们只⽤处理「加减乘除」混合运算即可。根据四则运算的顺序,我们可以先计算乘除法,然后再计算加减法。由此,我们可以得出下⾯的结论:
• 当⼀个数前⾯是 ‘+’ 号的时候,这⼀个数是否会被⽴即计算是「不确定」的,因此我们可以先压⼊栈中;
• 当⼀个数前⾯是 ‘-’ 号的时候,这⼀个数是否被⽴即计算也是「不确定」的,但是这个数已经和前⾯ 的 - 号绑定了,因此我们可以将这个数的相反数压⼊栈中;
• 当⼀个数前⾯是 ‘*’ 号的时候,这⼀个数可以⽴即与前⾯的⼀个数相乘,此时我们让将栈顶的元素乘上这个数;
• 当⼀个数前⾯是 ‘/’ 号的时候,这⼀个数也是可以⽴即被计算的,因此我们让栈顶元素除以这个数。
当遍历完全部的表达式的时候,栈中剩余的「元素之和」就是最终结果。
class Solution {
public:
int calculate(string s) {
vector<int> nums;//存储数字
char op='+';
int n=s.size();
int i=0;
while(i<n)
{
//如果为数字
if('0'<=s[i]&&s[i]<='9')
{
//多位数的情况
int temp=0;
while(i<n&&'0'<=s[i]&&s[i]<='9')
{
temp=temp*10+(s[i++]-'0');
}
if(op=='+')
{
nums.push_back(temp);
}
else if(op=='-')
{
nums.push_back(-temp);
}
else if(op=='*')
{
nums.back()*=temp;
}
else
{
nums.back()/=temp;
}
}
//如果为空格
else if(s[i]==' ')
{
i++;
}
//如果为其他符合
else
{
op=s[i];
i++;
}
}
int ret=0;
for(auto e:nums)
{
ret+=e;
}
return ret;
}
};对于 3[ab2[cd]] ,我们需要先解码内部的,再解码外部(为了⽅便区分,使⽤了空格):
因此我们可以定义两个栈结构,⼀个⽤来保存解码前的重复次数 k (左括号前的数字),⼀个⽤来保存解码之前字符串的信息(左括号前的字符串信息)。
class Solution {
public:
string decodeString(string s) {
stack<int> nums; // 栈用于存储重复次数的数字
stack<string> st; // 栈用于存储当前的字符串
st.push(""); // 初始化栈顶为一个空字符串,用于存储最外层的解码结果
int n = s.size(), i = 0;
while (i < n) {
// 如果当前字符是数字,则处理数字(可能是多位数)
if ('0' <= s[i] && s[i] <= '9') {
int temp = 0;
while (i < n && '0' <= s[i] && s[i] <= '9') {
temp = temp * 10 + (s[i] - '0'); // 将字符转为整数
i++;
}
nums.push(temp); // 将处理好的数字压入数字栈
}
// 如果当前字符是左括号 '['
else if (s[i] == '[') {
i++; // 跳过左括号
string temp;
while (i < n && 'a' <= s[i] && s[i] <= 'z') {
temp += s[i++]; // 记录括号中的字符串
}
st.push(temp); // 将当前字符串压入字符串栈
}
// 如果当前字符是右括号 ']'
else if (s[i] == ']') {
i++; // 跳过右括号
int k = nums.top(); // 获取数字栈顶元素(重复次数)
nums.pop(); // 弹出数字栈顶
string temp = st.top(); // 获取当前字符串栈顶的字符串
st.pop(); // 弹出字符串栈顶
// 将字符串重复 k 次并追加到上一级的字符串
while (k--) {
st.top() += temp; // 将重复的结果追加到栈顶的字符串
}
}
// 如果当前字符是字母
else {
string temp;
while (i < n && 'a' <= s[i] && s[i] <= 'z') {
temp += s[i++]; // 累加连续的字母
}
st.top() += temp; // 追加到当前的栈顶字符串
}
}
return st.top(); // 返回最外层的解码结果
}
};为什么在 st 中先推入一个空字符串 ""?
处理最外层字符串的特殊情况:
示例解释 以输入字符串 “3[a2[bc]]” 为例: 初始化:st = [“”],nums = []。 解析 3:将 3 压入 nums,nums = [3]。 遇到 [:推入空字符串到 st,st = [“”, “”]。 解析 a:将 a 追加到 st.top(),st = [“”, “a”]。 解析 2:将 2 压入 nums,nums = [3, 2]。 遇到 [:推入空字符串到 st,st = [“”, “a”, “”]。 解析 bc:将 bc 追加到st.top(),st = [“”, “a”, “bc”]。 遇到 ]:弹出 2 和 bc,重复 bc 两次,st = [“”, “a”,“bcbc”]。 遇到 ]:弹出 3 和 a + bcbc,重复结果三次,st = [“”]。 返回最终结果 st.top() 为"abcbcabcbcabcbc"。
⽤栈来模拟进出栈的流程。
class Solution {
public:
bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
stack<int> st;
int m=pushed.size();
int n=popped.size();
int i=0;
if(m!=n)
{
return false;
}//如果元素个数不相等一定不匹配
for(auto e:pushed)
{
st.push(e);
while(!st.empty()&&st.top()==popped[i])
{
st.pop();
i++;
}
}
return st.empty();
}
};在信息的海洋中,栈是一叶扁舟,承载着计算的重量,也承载着思想的深邃。它的操作简单而纯粹,却蕴含着无限的可能性。或许,这正是栈的魅力所在——在有限中追寻无限,在简单中窥见复杂。在这座无形的山峰上,我们每一步都通向更高的远方。
本篇关于栈算法的介绍就暂告段落啦,希望能对大家的学习产生帮助,欢迎各位佬前来支持斧正!!!