代码随想录算法训练营第十一天|20 有效的括号 1047 删除字符串中的所有相邻重复项 150 逆波兰表达式求值
LeetCode 20 有效的括号
题目链接: 20.有效的括号
思路:括号匹配是使用栈解决的经典问题,在编译原理中,编译器在词法分析的过程中处理括号和花括号等符号的符号逻辑也是使用了栈的数据结构
首先分析不匹配的几种情况:
①第一种情况:字符串里左方向的括号多余;
此种情况当已遍历完字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,return false
②第二种情况:括号没有多余,但是括号的类型没有匹配上;
此种情况在遍历字符串匹配的过程中发现栈里没有要匹配的字符,return false
③第三种情况:字符串里右方向的括号多余。
此种情况在遍历字符串匹配的过程中,栈已经为空,没有匹配的字符,但是右括号没有找到对应的左括号,return false
注:当且仅当遍历完字符串匹配后,发现栈是空的,说明左右括号全部匹配
class Solution{
public:
bool isVail(string s) {
if(s.size() % 2 != 0) return false; //如果s的长度为奇数,一定不匹配
stack<char> st;
for(int i = 0; i < s.size(); i++) {
if(s[i] == '(') st.push(')');
else if(s[i] == '[') st.push(']');
else if(s[i] == '{') st.push('}');
//接下来进行出栈匹配
else if(st.empty() || s[i] != st.top()) { //当对比栈中为空或者遇到非左方向的括号跟栈顶字符不匹配的情况,包含第二和第三种情况
return false;
}
else {
st.pop(); //栈顶元素和s[i]字符匹配,弹出
}
}
return st.empty(); //此时如果栈为空即说明已完成匹配,非空说明处于第一种情况
}
};
LeetCode 1047 删除字符串中的所有相邻重复项
题目链接: 1047.删除字符串中的所有相邻重复项
思路:与上一题消除括号的思想相同,删除相邻重复项完全可以在对比栈存放遍历过的元素,然后进行对应的消除操作
class Solution {
public:
string removeDuplicates(string S) {
stack<char> st;
for(int i = 0; i < S.size(); i++) {
if(st.empty() || st.top() != S[i]) { //当且仅当栈为空或者栈顶元素不等于遍历元素时
st.push(S[i]);
}
else { //删除重复字符
st.pop();
}
}
//存放新字符
string res;
while(!st.empty()) {
res += st.top();
st.pop();
}
//由于栈的出栈特性,需要将字符顺序反转
reverse(res.begin(), res.end());
return res;
}
};
此题可以考虑将字符串直接作为栈,省去栈转为字符串的操作
class Solution {
public:
string removeDuplicates(string S) {
string res;
for(char s:S) {
if(res.empty() || res.back() != s) {
res.push_back(s);
}
else {
res.pop_back();
}
}
return res;
}
};
此类消除问题首先应该想到用栈来进行解决,很多编程功能实现都需要使用栈结构,实现函数递归就需要栈。
**递归的实现:**每次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,在递归返回的时候,从栈顶弹出上一次递归的各项参数,这也能解释递归为什么可以返回上一层位置的原因。
此时可能会遇到栈溢出报错,可能是在使用递归的时候出现了无限递归。
LeetCode 150 逆波兰表达式求值
题目链接: 150.逆波兰表达式求值
逆波兰表达式是一种后缀表达式,即运算符写在后面,且逆波兰表达式去掉括号后无歧义,适合用栈操作运算。
思路:遇到数字字符就入栈,遇到运算符字符就将栈顶两个元素进行计算,并将计算结果继续入栈,本质思想与上题及上上题类似。
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> st;
for (int i = 0; i < tokens.size(); i++) {
if (tokens[i] == "+"
|| tokens[i] == "-"
|| tokens[i] == "*"
|| tokens[i] == "/") {
int a = st.top();
st.pop();
int b = st.top();
st.pop();
if (tokens[i] == "+") st.push(b + a);
if (tokens[i] == "-") st.push(b - a);
if (tokens[i] == "*") st.push(b * a);
if (tokens[i] == "/") st.push(b / a);
}
else {
st.push(stoi(tokens[i]));
}
}
return st.top();
}
};
逆波兰表达式的运算符后缀方式对于计算机来说是很友好的,运算符中缀对我们来说容易理解,但对计算机来说不友好。
通过上述三种题型,需要熟悉在什么情况下应该考虑采用栈来进行处理。