代码随想录算法训练营第11天| 20. 有效的括号、1047. 删除字符串中的所有相邻重复项、150. 逆波兰表达式求值
2024-3-24
这几天复习了408王道数据结构的栈和队列部分,刚好最近也要准备蓝桥杯,因此重新开始训练营学习,顺便巩固学习成果。
20. 有效的括号
学习前的想法
左括号进栈,遇到右括号就和栈顶左括号进行比较,相配则继续,不相配则返回false。
如果遇到右括号,但此时栈中没有左括号,也直接返回false。
遍历完字符串后,如果栈空,则说明全部相符,否则有多余的括号。
class Solution {
public:
bool isValid(string s) {
stack<char> stack;
for(int i = 0; i < s.size(); i++) {
if(s[i] == '(' || s[i] == '[' || s[i] == '{') stack.push(s[i]);
if(s[i] == ')') {
if(stack.empty()) return false;
if(stack.top() == '(') stack.pop();
else return false;
}
if(s[i] == ']') {
if(stack.empty()) return false;
if(stack.top() == '[') stack.pop();
else return false;
}
if(s[i] == '}') {
if(stack.empty()) return false;
if(stack.top() == '{') stack.pop();
else return false;
}
}
if(stack.empty()) return true;
return false;
}
};
2024-3-24
成功ac
学习后的想法
括号匹配是使用栈解决的经典问题。
由于栈结构的特殊性,非常适合做对称匹配类的题目。
在写这种模拟类的题目的时候,一定要先分析好所有的情况,这样才能避免写的过程中混乱。
实现
代码随想录的实现基本上和我的实现一样,但是用了一些小技巧,可以减少判断次数。
1047. 删除字符串中的所有相邻重复项
题目链接:1047. 删除字符串中的所有相邻重复项
文档讲解:1047. 删除字符串中的所有相邻重复项
视频讲解:
目标:
状态:
学习前的想法
题目给出一个由小写字母组成的字符串s,我们需要重复比较字符串中相邻的两个字符,如果相同,就把它们都删除。
例如输入字符串abbaca
对应的输出字符串为ca
。
我采用栈来处理这种问题,字符串首元素进栈,之后每个元素与栈顶元素作比较,相等则弹出栈顶元素,否则该元素进栈,遍历字符串完毕后,输出栈中所有元素。
尝试实现代码:
class Solution {
public:
string removeDuplicates(string s) {
stack<char> s1;
stack<char> s2;
for(int i = 0; i < s.size(); i++) {
if(s1.empty()) s1.push(s[i]);
else {
if(s[i] == s1.top()) s1.pop();
else s1.push(s[i]);
}
}
while(!s1.empty()) {
s2.push(s1.top());
s1.pop();
}
string n = "";
while(!s2.empty()) {
n += s2.top();
s2.pop();
}
return n;
}
};
2024-3-25
成功ac,但是最后怎么把栈中的字符全部去除是一个值得注意的点,我的方法很蠢,又声明了一个栈来重新排序。
学习后的想法
基本和我思路一致,学到了可以使用reverse()
函数来翻转字符串。
同时学到了,可以直接使用string来模拟一个栈,这样最后就不需要再进行出栈,反转字符串的操作了。
实现
这里给出使用string来模拟栈的代码:
string result;
for(char s : S) {
if(result.empty() || result.back() != s) {
result.push_back(s);
}else {
result.pop_back();
}
return result;
}
150. 逆波兰表达式求值
题目链接:150. 逆波兰表达式求值
文档讲解:150. 逆波兰表达式求值
视频讲解:
目标:
状态:
学习前的想法
这几天在复习数据结构的时候,学到了这里。
根据王道讲解,波兰表达式为前缀表达式,逆波兰表达式实际上就是后缀表达式,这两者的区别是运算符号前者会安置在表达式左侧即前缀,而后者会安置在右侧,即后缀。这样可以明确每个运算符的运算顺序,而不需要使用括号来进行认为划分,更方便计算机处理。
我们平常使用的实际上是中缀表达式。
准备一个栈用来存储数字,对于一个给定的逆波兰表达式,对其进行遍历,遇到数字则进栈,遇到运算符则从栈中弹出两个数进行运算,先弹出的数为右操作数,将算出的结果入栈。
尝试实现代码:
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> stack;
int right,left;
for(string s : tokens) {
if(s == "+") {
right = stack.top();
stack.pop();
left = stack.top();
stack.pop();
stack.push(left + right);
}
else if(s == "-") {
right = stack.top();
stack.pop();
left = stack.top();
stack.pop();
stack.push(left - right);
}
else if(s == "*") {
right = stack.top();
stack.pop();
left = stack.top();
stack.pop();
stack.push(left * right);
}
else if(s == "/") {
right = stack.top();
stack.pop();
left = stack.top();
stack.pop();
stack.push(left / right);
}
else {
stack.push(stoi(s));
}
}
return stack.top();
}
}
2024-3-27
由于不知道如何将字符串转换为int整型,我上网查询到stoi()
函数可以直接实现。
学习后的想法
和我思路基本一致。
今天学习数据结构的时候也学到了二叉树的前中后序遍历,逆波兰表达式实际上相当于是二叉树中的后续遍历。可以把运算符当作中间节点构造一棵二叉树,实际上编译原理里的语义分析树好像也是这样得来的🤔。
实现
卡哥的实现和我基本一样,不过使用了long long
防止溢出,然后字符串转为整型的函数用的和我搜索到的也是一样的stoll()
,因为卡哥用的long long
所以是ll。
收获与学习时长
学习时长: h min
没有计算具体的时间,不过也许是因为前几天刚复习国408数据结构栈与队列的原因,还是比较轻松的。
收获
熟练了书本上知识的代码实现,思路变得更清晰。