目录
- 一、[删除字符串中的所有相邻重复项](https://leetcode.cn/problems/remove-all-adjacent-duplicates-in-string/description/)
- 二、[比较含退格的字符串](https://leetcode.cn/problems/backspace-string-compare/description/)
- [三、[基本计算器 II](https://leetcode.cn/problems/basic-calculator-ii/description/)](#三、基本计算器 II)
- 四、[字符串解码](https://leetcode.cn/problems/decode-string/description/)
- 五、[验证栈序列](https://leetcode.cn/problems/validate-stack-sequences/description/)
- 结尾
一、删除字符串中的所有相邻重复项
题目描述:
思路讲解:
本题的目的很简单,看见两个相邻且相同的字符时,将这两个字符从字符串中删除,删除这两个字符之后可能会出现前后两个字符变为相邻相同的情况,所以需要重复进行删除的操作。
本题可以使用栈来解决,定义一个变量i来遍历字符串,对下面不同情况分类讨论:
- 当栈中没有元素或是栈顶元素与下标i对应的元素不同时,将下标i对应的元素放入栈中
- 当栈顶元素与下标i对应的元素不同时,将栈顶元素删除,并将i向右移动,但是新的栈顶元素和新下标i对应元素可能也会相同,如果多次满足这个情况则需要重复这个操作
当完成上面的操作后,再将栈中的元素取出组成字符串,但是取出来的字符串是逆序的,我们需要逆转后再返回,所以本题可以使用数组来模拟栈,取出来组成的字符串就可以直接返回。
编写代码:
cpp
class Solution {
public:
string removeDuplicates(string s) {
string ans;
int sLen = s.size();
int ansi = -1;
for(int i = 0 ; i < sLen ; i++)
{
// 遇到相邻或消除相邻后字母相邻的消除
while(ansi >= 0 && ans[ansi] == s[i])
{
ans.pop_back();
ansi--;
i++;
}
if(i < sLen)
ans += s[i];
ansi++;
}
return ans;
}
};
二、比较含退格的字符串
题目描述:
思路讲解:
本题与上一题的思路基本一致,上一题是前面一个字符和后面一个字符相同时,删除这两个字符,本题是后面一个字符是'#'就删除前面一个字符和'#'。
使用数组来模拟栈,定义一个变量i来遍历字符串,对下面不同情况分类讨论:
- 当下标i对应的字符不为'#'时,将i位置上的字符添加到栈中
- 当下标i对应的字符为'#'时,删除栈顶元素并且i向右移动
使用这个方法对两个字符串进行处理,最终会得到两个数组,将数组中的字符处理成两个字符串进行比较,相同返回true,不相同返回false。
编写代码:
cpp
class Solution {
public:
bool backspaceCompare(string s, string t) {
string tmp1 , tmp2;
for(auto ch : s)
{
if(ch != '#')
tmp1 += ch;
else if(tmp1.size() > 0)
tmp1.pop_back();
}
for(auto ch : t)
{
if(ch != '#')
tmp2 += ch;
else if(tmp2.size() > 0)
tmp2.pop_back();
}
if(tmp1 == tmp2) return true;
else return false;
}
};
三、基本计算器 II
题目描述:
思路讲解:
本题只有'+', '-', '*', '/'
这四个运算符,所以相对来说还是比较简单的,当我们遍历到数组中的'+'
和'-'
时,由于不知道后面一个数的运算符是什么,所以不能将前后的两个数字进行直接运算,那么我们就需要选择一个容器将数字存起来,这里我们选择栈来存储数字。
这里我们定义一个栈nums来存储数字,定义一个char op
来记录某一个整数前的运算符,由于本题中出现的所有整数都是正整数,就建op设置为+,再定义一个变量i来遍历数组,遍历数组时,我们将出现的情况分为四种:
- 空格,当i指向的元素为空格时,仅需i向右移即可
- 数字,当i指向的元素为数字时,由于数字是由字符串形式存在的,我们需要将它提取出来,定义一个变量sum,当连续出现字母时,i每指向数字时,就先将sum*10,再将sum加上i指向的数字,最后i向右移动
- 运算符
'+'
和'-'
,当运算符为这两个时,将op修改为当前的运算符,这时我们并不能将运算符前后的两个数字进行运算,所以先将刚刚提取出来的数字带上运算符的属性添加到栈中,最后i向右移动 - 运算符
'*'
和'/'
,将op修改为当前的运算符,这两个运算符在本题中的优先级最高,遇到后只需要将该运算符前后两个数字进行运算即可,也就是取出栈顶元素和提取后面的数字再进行运算,最后将运算的结果放入到栈中,最后i向右移动
由于我们将数字加入到栈中时,都是带来+或-的,做完上面的操作后,我们就将-、/、*这三个运算符处理完了,最后只需要将栈中所有的数字相加即可得到本题的答案。
编写代码:
cpp
class Solution {
public:
int calculate(string s) {
char op = '+'; // 记录某个整数前面的运算符
stack<long long> nums; // 栈中存储数字
int sLen = s.size();
for(int i = 0 ; i < sLen ;)
{
// s[i] 是空格时
if(s[i] == ' ') i++;
// s[i] 为运算符时
if(s[i] == '+' || s[i] == '-' || s[i] == '*' || s[i] == '/')
op = s[i++];
// s[i] 是空格时
if(s[i] == ' ') i++;
long long tmp = 0;
while('0' <= s[i] && s[i] <= '9')
{
tmp = tmp * 10 + s[i++] - '0';
}
// s[i] 是空格时
if(s[i] == ' ') i++;
if(op == '+')
nums.push(tmp);
else if(op == '-')
nums.push(-tmp);
else if(op == '*')
nums.top() *= tmp;
else if(op == '/')// op == '/'
nums.top() /= tmp;
}
int ans = 0;
while(!nums.empty())
{
ans += nums.top();
nums.pop();
}
return ans;
}
};
四、字符串解码
题目描述:
思路讲解:
当我们遍历到'['
时,需要将[]
中的字符串变为原来的k倍,我们并不知道[]
中的字符串中是否还存在'[]'
,所以就需要将[
之前的数字和[
之后的字符串分别存储起来,这里我们选择定义两个栈来分别存储数字和字符串。
定义一个字符串栈stStr和一个数字栈stNum,再定义一个变量i来遍历数组,遍历数组时,我们将出现的情况分为四种:
- 遇到数字,将这个数字放入到数字栈中
- 遇到
'['
,把后面的字符串提取出来放到字符串栈中 - 遇到
']'
,将字符串栈栈顶元素和数字栈栈顶元素提取出来,按照题目中的方式进行处理后,再放入到字符串栈中 - 遇到单独的字符,提取出这个字符串,将这个字符串放入到字符串栈栈顶的字符串的后面
把上面的操作做完后,字符串栈中仅剩的字符串就是本题的答案,取出来并返回即可解决本题。
本题由于个小细节就是需要在字符串栈中先添加一个空字符串,这样能够保证对两个栈的处理过程相同。
编写代码:
cpp
class Solution {
public:
string decodeString(string s) {
stack<string> stStr;
stack<int> stNum;
int flag = 0; // 标记前面是否出现过[
// 这里字符串栈先入一个空字符串
// 使后面字符串接到字符串栈栈顶的操作保持一致
// 不需要再判断是否为空栈的情况
stStr.push("");
int sLen = s.size();
for(int i = 0 ; i < sLen ; )
{
int tmpNum = 0;
// 数字后面必定是[
while('0' <= s[i] && s[i] <= '9')
{
tmpNum = tmpNum * 10 + s[i++] - '0';
}
// 这里可能没有数字
if(tmpNum)
stNum.push(tmpNum);
// 当s[i] 为 [ 时将flag标记为1
if(s[i] == '[')
{
flag = 1;
i++;
}
// 提取连续的字符串
string tmp = "";
while('a' <= s[i] && s[i] <= 'z')
{
tmp += s[i++];
}
// 遇到[就将后面的字符串入字符串栈
// 没遇到[就将后面出现的字符串接到字符串栈栈顶元素的后面
if(flag == 1)
stStr.push(tmp);
else
stStr.top() += tmp;
// 遇到]则取出数字栈栈顶的数字(n个),和字符串栈栈顶的字符串(s)
// 变为 n 个 s相连接,再接到字符串栈栈顶元素的后面
if(s[i] == ']')
{
int num = stNum.top();
stNum.pop();
string str;
while(num--)
str += stStr.top();
stStr.pop();
stStr.top() += str;
// 不能再判断条件哪里i++
// 这里可能是数字
i++;
}
// 标记变回0
flag = 0;
}
return stStr.top();
}
};
五、验证栈序列
题目描述:
思路讲解:
本题只需要定义一个栈,然后对push和pop进行模拟即可完成本题。
定义一个栈st,定义两个变量pushi和popi分别用来遍历pushed数组和poped数组,首先将pushi指向的元素放入到栈中,再使栈顶元素与popi指向的元素进行对比,会出现两种情况:
- 栈顶元素与popi指向的元素不同,pushi向右移动
- 栈顶元素与popi指向的元素相同,删除栈顶元素,popi向后移动,重复与栈顶元素进行对比,直到不相同或是栈为空
当上面的操作做完以后有两种方式判断推入 push 和弹出 pop 操作序列是否为正确的序列,一是栈为空则是正确的序列,二是popi遍历到poped数组的结尾是正确的序列,选择其中的一个方式即可。
编写代码:
cpp
class Solution {
public:
bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
stack<int> st;
int pushLen = pushed.size();
int popLen = popped.size();
int pushi = 0 , popi = 0;
while(pushi < pushLen)
{
if(st.empty() || st.top() != popped[popi])
st.push(pushed[pushi++]);
while(!st.empty() && st.top() == popped[popi])
{
st.pop();
popi++;
}
}
if(st.empty())
return true;
else
return false;
}
};
结尾
如果有什么建议和疑问,或是有什么错误,大家可以在评论区中提出。
希望大家以后也能和我一起进步!!🌹🌹
如果这篇文章对你有用的话,希望大家给一个三连支持一下!!🌹🌹