20. 有效的括号
本题是使用栈的经典题目,思路就是遍历字符串的时候匹配栈中的元素来达到消除的目的。有两种方法,一种是左括号入栈,还有一种是右括号入栈。
使用unordered_map
储存左右括号,其中key是右括号,value是左括号,也就是使用左括号先入栈的方式来解决,代码如下:
class Solution {
public:
bool isValid(string s) {
unordered_map<char,char> bracket;
bracket.insert({pair<char,char>(')','('),
pair<char,char>(']','['),
pair<char,char>('}','{')});
stack<char> st;
for(int i = 0; i < s.size(); i++){
if(bracket.find(s[i]) == bracket.end()){
st.push(s[i]);
}else{
if(st.empty()) return false;
if(st.top() == bracket.find(s[i])->second) st.pop();
else st.push(s[i]);
}
}
if(st.empty()) return true;
else return false;
}
};
如果当前遍历的元素在map中能找到匹配的项,再去和栈顶的元素比较,相同就消除,if(st.empty()) return false;
是一个剪枝的操作。自己写的代码有些逻辑是可以合并的,还可以进一步简化,下面看另一种写法。
如果使用右括号先入栈,然后再讨论几种无法匹配括号消除的情况,直接使用多个if else语句完成。如果输入的是左括号,就往栈中push右括号;如果输入的是右括号,就和栈顶匹配是否相等。有点逆向思维的意思,就像卡哥说的:技巧性的东西没有固定的学习方法,还是要多看多练,自己灵活运用了。
下面是代码:
bool isValid(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(']');
// 第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号 return false
// 第二种情况:遍历字符串匹配的过程中,发现栈里没有我们要匹配的字符。所以return false
else if (st.empty() || st.top() != s[i]) return false;
else st.pop(); // st.top() 与 s[i]相等,栈弹出元素
}
return st.empty();
1047. 删除字符串中的所有相邻重复项
其实这题比20. 有效的括号要简单点,栈匹配时的操作比较简单,也不用讨论情况。在处理完栈后再处理字符串即可。
class Solution {
public:
string removeDuplicates(string s) {
stack<char> st;
for(int i = 0; i < s.size(); i++){
if(st.empty()) st.push(s[i]);
else{
if(s[i] == st.top()){
st.pop();
continue;
}else{
st.push(s[i]);
}
}
}
int len = st.size();
s.resize(len);
for(int i = len - 1; i >= 0; i--){
s[i] = st.top();
st.pop();
}
return s;
}
};
或者使用string直接操作:
string removeDuplicates(string S) {
string result;
for(char s : S) {
if(result.empty() || result.back() != s) {
result.push_back(s);
}
else {
result.pop_back();
}
}
return result;
}
匹配问题都可以使用栈来做。
150. 逆波兰表达式求值
本题的思路很简单,就是遇到数字时,将其压入栈中,遇到符号从栈中取出栈顶的两个运算得出结果再压入栈中,知道vector遍历结束。但是因为本题使用的输入是vector<string>
所以需要注意下:
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<long long> st;
for (int i = 0; i < tokens.size(); i++) {
if (tokens[i] == "+" || tokens[i] == "-" || tokens[i] == "*" || tokens[i] == "/") {
long long num1 = st.top();
st.pop();
long long num2 = st.top();
st.pop();
if (tokens[i] == "+") st.push(num2 + num1);
if (tokens[i] == "-") st.push(num2 - num1);
if (tokens[i] == "*") st.push(num2 * num1);
if (tokens[i] == "/") st.push(num2 / num1);
} else {
st.push(stoll(tokens[i]));
}
}
int result = st.top();
st.pop(); // 把栈里最后一个元素弹出(其实不弹出也没事)
return result;
}
};
首先看到栈使用的是stack<long long>
,其次在不需要运算push的时候,使用stoll(tokens[i])
类型转换;另一个需要注意的地方是num1
和num2
的顺序。