20. 有效的括号
题目链接:Leetcode20. 有效的括号
文章讲解:代码随想录—20.有效的括号
思路:
因为三种括号一一匹配,所以本题最好的解决办法就是用栈。
不符合题意的情况有三种:1. 左括号多余 2. 右括号多余 3. 左右括号不匹配
因此可以先按顺序判断字符串中括号类型,如果是左括号,就向栈里传入对应的右括号;如果是右括号,就验证栈顶的右括号与字符串的右括号是否相同,不相同就返回 false。如果验证过程中栈提前变空,或者验证结束后栈内还有元素剩余,则返回false。
class Solution {
public:
bool isValid(string s) {
if (s.size() % 2 != 0) return false;
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() || st.top() != s[i]) return false;
else st.pop();
}
return st.empty();
}
};
时间复杂度:O(n)
空间复杂度:O(n)
1047. 删除字符串中的所有相邻重复项
题目链接:Leetcode1047. 删除字符串中的所有相邻重复项
文章讲解:代码随想录—1047. 删除字符串中的所有相邻重复项
思路:
本题和上一题有效括号的思路是一样的,都是把要查找的匹配项放进栈中,如果匹配就弹出。
class Solution {
public:
string removeDuplicates(string s) {
stack<char> st;
for (auto i : s) {
if (st.empty() || st.top() != i) st.push(i);
else st.pop();
}
string res;
while (!st.empty()) {
res += st.top();
st.pop();
}
reverse(res.begin(), res.end());
return res;
}
};
时间复杂度:O(n)
空间复杂度:O(n)
优化在于,可以不用单独申请栈,直接用string就能解决问题。
class Solution {
public:
string removeDuplicates(string s) {
string res;
for (auto i : s) {
if (res.empty() || res.back() != i) res.push_back(i);
else res.pop_back();
}
return res;
}
};
时间复杂度:O(n)
空间复杂度:O(1)
150. 逆波兰表达式求值
文章讲解:代码随想录—150. 逆波兰表达式求值
思路:
这个题的解法很多,可以用二叉树解决,可以用递归解决,在这里介绍栈解决方法
在前几个题的铺垫下,这个题变得异常简单。只是注意最后把 vector<string> 的元素推进到 long long 数据结构的栈中的时候,要进行转换,用 stoll 可以把 string 类型转换成 long long 类型。
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<long long> st;
for (auto s : tokens) {
if (s == "+" || s == "-" || s == "*" || s == "/") {
long long num1 = st.top();
st.pop();
long long num2 = st.top();
st.pop();
if (s == "+") st.push(num2 + num1);
if (s == "-") st.push(num2 - num1);
if (s == "*") st.push(num2 * num1);
if (s == "/") st.push(num2 / num1);
}
else st.push(stoll(s));
}
return st.top();
}
};
时间复杂度:O(n)
空间复杂度:O(n)
总结
栈适用于查找匹配和匹配消除的题,递归问题基本也都能用栈解决。
在企业项目开发中,尽量不要使用递归,在项目比较大的时候,由于参数多,全局变量等等,使用递归很容易判断不充分return的条件,非常容易无限递归(或者递归层级过深),造成栈溢出错误