20 有效的括号
有三种不匹配的情况
- 第一种情况,字符串里左方向的括号多余了 ,所以不匹配。
( ( [ { } ] )
- 第二种情况,括号没有多余,但是括号的类型没有匹配上
( [ { } } }
- 第三种情况,字符串的右方向的括号多余了
( [ { } ] ) ) )
思路:在遍历前一半字符串的时候,在栈中放入匹配的括号,在遍历后一半后如果栈中为空,说明全部匹配上
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();
}
};
#1047. 删除字符串中的所有相邻重复项
和上一题都是相同的思路,在遍历数组时,将遍历过的元素存放在栈中(其实栈中的top()就是正在遍历的元素前面的,s[i]和top()比较是否一致是判断s[i]是否需要放入栈中,当时一直不太明白这个地方),如果st.top()==s,说明实现对对碰,如果st.top()!=s,说明没有对对碰接着遍历数组
class Solution {
public:
string removeDuplicates(string S) {
stack<char> st;
for(char s:S){
//这个地方一开始没看懂 st.top()就相当于把s的前一个元素存入
//st.top()!=s就是在比较s和s前面的 如果栈为空说明刚开始遍历数组 要存入栈
//如果st.top()!=s说明正在遍历的s和前面的不是对对碰的情况 就放入栈
if(st.empty() || st.top()!=s){
st.push(s);
}else { //说明s和前面的元素对对碰没了
st.pop();
}
}
string result="";
while(!st.empty()){ //如果栈不为空 就是最后结果的反转字符
result+=st.top(); //将栈中的字符全部出栈
st.pop();
}
reverse(result.begin(),result.end());
return result;
}
};
150. 逆波兰表达式求值
逆波兰表达式:是一种后缀表达式,所谓后缀就是指运算符写在后面。
平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:
- 去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
- 适合用栈操作运算:遇到数字则入栈;遇到运算符则取出栈顶两个数字进行计算,并将结果压入栈中。
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); //要注意这个地方的顺序 是num2/num1
}else{
//将数字压入栈
st.push(stoll(tokens[i]));
}
}
int result=st.top();
st.pop();
return result;
}
};