第一题
学习记录:
将每一对有效的括号通过栈来排除:遇到左括号如"("、"["、"{"时入栈,遇到右括号")"、"]"、"}"时,检查栈顶元素是否是对应的左括号,如果是则出栈,否则返回`false`。最后,如果栈为空,返回`true`,否则返回`false`。
根据提示自己写的:
class Solution {
public:
bool isValid(string s) {
stack<char> words;
if (s.size() % 2 == 1) return false;
for (char c:s) {
if ((c == '(' || c == '[' || c == '{')) words.push(c);
else {
if (words.empty()) return false;
else if (c == ')' && words.top() == '(') {
words.pop();
}
else if (c == ']' && words.top() == '[') {
words.pop();
}
else if (c == '}' && words.top() == '{') {
words.pop();
}
else return false;//避免跳过非匹配括号
}
}
if (words.empty()) return true;
else return false;
}
};
代码随想录的:
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(); // st.top() 与 s[i]相等,栈弹出元素
}
// 第一种情况:此时我们已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false,否则就return true
return st.empty();
}
};
第二题
自己写的老提示超出内存限制,明明和代码随想录的一模一样,我不懂为什么:
class Solution {
public:
string removeDuplicates(string s) {
stack<char> words;
for (auto c:s) {
if (words.empty() || c != words.top()) words.push(c);
else words.pop();
}
string result="";
while(!words.empty()) {
result = result + words.top();
words.pop();
}
reverse (result.begin(), result.end()); // 此时字符串需要反转一下
return result;
}
};
学习记录:
看了力扣上别人的评论才知道问题出在result = result + words.top()上, 参考C#和C++字符串拼接的性能分析_c# tostring性能_Real_JumpChen的博客-CSDN博客
所以能写str+='a'就写这个!
TIPS:
翻转函数:reverse(str.begin(), str.end())
定义size:str.resize()
此外string本身也可以当作栈使用:
class Solution {
public:
string removeDuplicates(string S) {
string result;
for(char s : S) {
if(result.empty() || result.back() != s) {
result.push_back(s);
}
else {
result.pop_back();
}
}
return result;
}
};
第三题
学习记录:
逆波兰表达式:是一种后缀表达式,所谓后缀就是指运算符写在后面。
平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
逆波兰表达式主要有以下两个优点:
-
去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
-
适合用栈操作运算:遇到数字则入栈;遇到运算符则取出栈顶两个数字进行计算,并将结果压入栈中。
自己采用switch经过GPT修改写的代码:
class Solution {
public:
int evalRPN(vector<string>& tokens) {
stack<int> num;
for (auto c:tokens) {
if (c == "+" || c == "-" || c == "*" || c == "/") {
int res = num.top();
num.pop();
switch (c[0]) { //因为c是string类型,需要判断的符号又都是单符号,因此c[0]==char类型的+-*/
case '+': res = num.top() + res; break; //case后跟整数类型
case '-': res = num.top() - res; break;
case '*': res = num.top() * res; break;
case '/': res = num.top() / res; break;
}
num.pop();
num.push(res);
}
else {
num.push(stoi(c));
}
}
return num.top();
}
};
TIPS:
- 在每个 case 语句后面,需要使用 break 语句来结束当前的 case,否则会发生所谓的 “fallthrough”,即程序会继续执行下一个 case 语句,直到遇到 break 语句或者 switch 语句的结束;
- 在 switch 语句的后面应该使用大括号 {} 而不是冒号 :;
`switch`语句在C++中只能用于整数类型(包括枚举类型)的变量或表达式,不可以直接用于字符串。
`c`在这里是一个`string`类型的变量。写`c[0]`其实是获取了这个字符串的第一个字符(`char`类型)。`char`类型在C++中被视为一种整数类型,所以可以在`switch`语句中使用它。例如,对于字符串`"+"`,`c[0]`就是字符`'+'`。因为所有的操作符都只有一个字符,所以使用`c[0]`是合适的。
代码随想录:
class Solution {
public:
int evalRPN(vector<string>& tokens) {
// 力扣修改了后台测试数据,需要用longlong
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]));
}
}
int result = st.top();
st.pop(); // 把栈里最后一个元素弹出(其实不弹出也没事)
return result;
}
};