代码随想录算法训练营第12天|20. 有效的括号|1047. 删除字符串中的所有相邻重复项|150. 逆波兰表达式求值
20. 有效的括号
讲完了栈实现队列,队列实现栈,接下来就是栈的经典应用了。
大家先自己思考一下 有哪些不匹配的场景,在看视频 我讲的都有哪些场景,落实到代码其实就容易很多了。
题目链接/文章讲解/视频讲解:https://programmercarl.com/0020.%E6%9C%89%E6%95%88%E7%9A%84%E6%8B%AC%E5%8F%B7.html
class Solution {
public:
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();
}
return st.empty();// 第一种情况:此时我们已经遍历完了字符串,
//但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false,否则就return true
}
};
总结
有三种出问题的情况
第一种情况,字符串里左方向的括号多余了 ,所以不匹配。 括号匹配1
第二种情况,括号没有多余,但是 括号的类型没有匹配上。 括号匹配2
第三种情况,字符串里右方向的括号多余了,所以不匹配。 括号匹配3
我们的代码只要覆盖了这三种不匹配的情况,就不会出问题,可以看出 动手之前分析好题目的重要性。
动画如下:
第一种情况:已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false
第二种情况:遍历字符串匹配的过程中,发现栈里没有要匹配的字符。所以return false
第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号return false
那么什么时候说明左括号和右括号全都匹配了呢,就是字符串遍历完之后,栈是空的,就说明全都匹配了。
分析完之后,代码其实就比较好写了,
但还有一些技巧,在匹配左括号的时候,右括号先入栈,就只需要比较当前元素和栈顶相不相等就可以了,比左括号先入栈代码实现要简单的多了!
通过与符合对称的性质,把对称放到堆栈中,在之后的下面操作消除之前对称符号,最后若堆栈为空则结果正确。
1047. 删除字符串中的所有相邻重复项
栈的经典应用。
要知道栈为什么适合做这种类似于爱消除的操作,因为栈帮助我们记录了 遍历数组当前元素时候,前一个元素是什么。
题目链接/文章讲解/视频讲解:https://programmercarl.com/1047.%E5%88%A0%E9%99%A4%E5%AD%97%E7%AC%A6%E4%B8%B2%E4%B8%AD%E7%9A%84%E6%89%80%E6%9C%89%E7%9B%B8%E9%82%BB%E9%87%8D%E5%A4%8D%E9%A1%B9.html
class Solution {
public:
string removeDuplicates(string s) {
stack<char>str;
for(char a:s)//定义a元素来遍历数组s
{
if(str.empty()||a!=str.top())//判断堆栈是否为空并将当前字符与栈顶比较
{
str.push(a);//不相同则放入堆栈中
}
else
{
str.pop();//把栈顶释放
}
}
string result="";
while(!str.empty())//筛选出剩下的元素放入result数组中
{
result+=str.top();
str.pop();
}
reverse(result.begin(),result.end());//放入数组是反的,所以反转一下。
return result;
}
};
总结
原理同上题,也就是字符串中元素与堆栈里面元素的消消乐。
150. 逆波兰表达式求值
本题不难,但第一次做的话,会很难想到,所以先看视频,了解思路再去做题
题目链接/文章讲解/视频讲解:https://programmercarl.com/0150.%E9%80%86%E6%B3%A2%E5%85%B0%E8%A1%A8%E8%BE%BE%E5%BC%8F%E6%B1%82%E5%80%BC.html
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]));
}
}
long long result=st.top();
st.pop();// 把栈里最后一个元素弹出(其实不弹出也没事)
return result;
}
};
总结
知识点:
1、stol()
此函数将在函数调用中作为参数提供的字符串转换为long int。它解析str并将其内容解释为指定基数的整数,并将其作为long int类型的值返回。
2、stoll()
此函数将在函数调用中作为参数提供的字符串转换为long long int。它解析str并将其内容解释为指定基数的整数,并将其作为long long int类型的值返回。
对二叉树的后序遍历,最后解出算法式子,把数字放入堆栈当中,然后遇到算数符,就得到堆栈两个数字并出栈,计算结果再压入到堆栈中进行后续计算。