20. 有效的括号
思路
遍历字符串s的时候,我们每碰到一个左括号就入栈一个它所匹配的右括号,碰到右括号的时候,看此时栈顶是否是相同类型的右括号,如果是,则这对括号是匹配的,如果不是相同类型或者没有括号,则就是不匹配或者是缺少右括号的。
cpp代码
class Solution {
public:
bool isValid(string s) {
stack<char> m; // 定义一个栈来存放遍历s时对应的右括号
for(int i = 0; i < s.size(); i++) {
if(s[i]=='(') m.push(')');
else if(s[i] == '{') m.push('}');
else if(s[i] == '[') m.push(']');
else if(!m.empty() && s[i] == m.top())
m.pop(); // 如果栈不为空,且s[i]与栈顶符号相同,则是对应上的,让它出栈
else return false; // 如果栈为空,或者s[i]与栈顶符号不相同,则没有对应上,返回false
}
}
return m.empty();
}
};
1047. 删除字符串中的所有相邻重复项
思路
这题跟上题差不多,不同的是它是用栈来存放“结果”,而上面是用栈来存放“中间值”。
cpp代码
class Solution {
public:
string removeDuplicates(string s) {
string m; // 作为“栈”存放字符
for(char c: s){
if(!m.empty() && c == m.back()) { // 若栈不为空,且栈顶与s[i]相同,即出现了相邻重复字符
m.pop_back(); // 那么就不要把当前字符放进栈,并且让重复的字符出栈
}
else m.push_back(c);
}
return m;
}
};
150. 逆波兰表达式求值
思路
后缀(逆波兰)表达式的求值方法:遇到数字则压入栈,遇到运算符则将栈顶元素出栈两次,将这两个数字进行对应运算符的运算,再将结果压入栈内,继续向后遍历运算。
例如:tokens = [“2”,“1”,“+”,“3”,“*”]。
- 遍历tokens序列,首先将"2"压入栈内,再将“1”压入栈内,栈内元素为(从栈底到栈顶):[“2”, “1”]。
- 然后下一个符号是“+”,这时我们让“1”出栈,让“2”出栈,运算2+1得到“3”,将结果压入栈内,此时栈内元素为:[“3”]。
- 继续遍历,将“3”压入栈内,此时栈内元素为:[“3”, “3”]。
- 继续遍历,遇到运算符“”,让栈顶“3”出栈,再让下一个“3”出栈,进行运算33,将结果“9”压入栈内,此时栈内只有:[“9”]。
- 遍历结束,栈顶元素“9”即为计算结果。
cpp代码
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<string> stack; // 设置一个栈来存放token
for(string s : tokens) {
if(s == "+" || s == "-" || s == "*" || s == "/") { // 如果当前token是运算符
// 就让栈顶的两个元素出栈
int b = stoi(stack.top());
stack.pop();
int a = stoi(stack.top());
stack.pop();
// 然后让他们两个进行对应运算符的运算,并将结果压入栈内
if(s == "+") stack.push(to_string(a+b));
else if(s == "-") stack.push(to_string(a-b));
else if(s == "*") stack.push(to_string(a*b));
else if(s == "/") stack.push(to_string(a/b));
}
else stack.push(s); // 如果当前token不是运算符,即数字,则入栈
}
return stoi(stack.top());
}
};