今日继续学栈与队列。
20.有效的括号
栈的经典题目,但比我上次做的那个复杂点,上次做的那个字符串只包含 ' ( ' 和 ' ) ' ,解法也很简单,遇到左括号就压入栈,遇到右括号就出栈,最后看字符串遍历完栈是否为空/栈为空时字符串是否遍历完就行了。但今天这个题复杂一点,字符串不仅有三种括号,而且要求左右括号必须一一配对。
题目内容:给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串 s
,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
我的代码:
class Solution {
public:
bool isValid(string s) {
if(s.size() % 2 != 0) return false;
stack<char> st;
for(auto i : s) {
if(i == '(') {
st.push(')');
}else if(i == '{') {
st.push('}');
}else if(i == '[') {
st.push(']');
}
if(i == ')' || i == '}' || i == ']') {
if(st.empty()) {
return false;
}
char temp = st.top();
st.pop();
if(temp != i) {
return false;
}
}
}
if(!st.empty()) return false;
return true;
}
};
思路:
括号不匹配无非三种情况:
1.左括号多了
2.右括号多了
3.左右括号不匹配
遇到一个左括号就把对应的右括号压入栈(如果直接把左括号压入栈的话,遍历到右括号的时候还要对类型配对进行判断,万一左右括号跳着来的就更复杂了),遇到右括号就弹出栈顶元素,相等则继续遍历,不相等直接return false,这处理了情况3;左括号多了那么对应的栈的元素也多了,这会导致遍历完了字符串栈还不为空,所以在循环结束时判一下空就好了,这处理了情况1;右括号多了即右括号还没遍历完栈就已经空了,所以在遍历到右括号的时候先判下栈是否为空。
视频里还提到了“剪枝”,即代码开头就判断字符串长度是否为奇数,是奇数的话一定不匹配,直接return false,我感觉这放某些赛制里可以骗分哎)并且尝试提交了一下竟然能通过59/74个用例...
1047.删除字符串中的所有相邻重复项
题目内容:给出由小写字母组成的字符串 S
,重复项删除操作会选择两个相邻且相同的字母,并删除它们。在 S 上反复执行重复项删除操作,直到无法继续删除。在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
示例:
输入:"abbaca"
输出:"ca"
解释:
例如,在 "abbaca" 中,我们可以删除 "bb" 由于两字母相邻且相同,这是此时唯一可以执行删除操作的重复项。之后我们得到字符串 "aaca",其中又只有 "aa" 可以执行重复项删除操作,所以最后的字符串为 "ca"。
我的代码:
class Solution {
public:
string removeDuplicates(string s) {
stack<char> st;
for(auto i : s) {
if(!st.empty()) {
char temp = st.top();
if(temp == i) {
st.pop();
continue;
}
}
st.push(i);
}
string result = "";
while(!st.empty()) {
result += st.top();
st.pop();
}
reverse(result.begin(), result.end());
return result;
}
};
思路:初始时栈为空,压入字符串第一个元素,往后继续遍历,栈不为空的时候将当前遍历元素与栈顶元素比较,一样的话将栈顶元素弹出,然后continue直接进入下一次循环;不一样的话就把该元素压入栈。栈里操作的是s元素的复制品,最后还要把栈里的元素转换为一个字符串再返回。思路就是一个个取出来放进字符串里,由于栈先入后出,所以还要翻转一下字符串再返回(自己写的时候根本没转换!)。代码随想录还提供了一种直接定义一个新字符串result,将result当栈使用(因为string可以操作back,push_back()和pop_back() )。
150.逆波兰表达式求值
题目内容:给你一个字符串数组 tokens
,表示一个根据 逆波兰表示法 表示的算术表达式。
请你计算该表达式。返回一个表示表达式值的整数。
示例 1:
输入:tokens = ["2","1","+","3","*"] 输出:9 解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
我的代码:
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 temp1 = st.top();
st.pop();
long long temp2 = st.top();
st.pop();
long long temp3 = 0;
if(tokens[i] == "+") {
temp3 = temp1 + temp2;
}else if(tokens[i] == "-") {
temp3 = temp2 - temp1;
}else if(tokens[i] == "*") {
temp3 = temp2 * temp1;
}else if(tokens[i] == "/") {
temp3 = temp2 / temp1;
}
st.push(temp3);
}else{
st.push(stoll(tokens[i]));
}
}
int res = st.top();
return res;
}
};
反思:这道题其实就是一个后缀表达式问题,思路是对的,遇到数字就入栈,遇到运算符就把两个数字弹出,计算结果,再让结果入栈,遍历完字符串数组的时候返回栈顶值就行。写的时候有以下几个误区:
1.栈里存放的是数字和计算的结果,应当为long long类型(力扣后台开的数字比较大)
2.tokens是一个字符串数组,因此判断该字符串是不是数组实际上并不容易,因为数字长度不定,判断运算符倒是很容易,判断完运算符剩余的字符串直接类型转换再压入栈就好了(类型转换也是新学的 stoi转换为int型,stoll转换为long long型)
3.判断字符时第一次写了tokens[i] == '+' ;tokens的元素都是字符串类型的,比较的时候要用双引号。
一天补两天卡,累死老娘了。。。