目录:
解题及思路学习
20. 有效的括号
https://leetcode.cn/problems/valid-parentheses/
给定一个只包括 '('
,')'
,'{'
,'}'
,'['
,']'
的字符串 s
,判断字符串是否有效。
有效字符串需满足:
- 左括号必须用相同类型的右括号闭合。
- 左括号必须以正确的顺序闭合。
- 每个右括号都有一个对应的相同类型的左括号。
示例 1:
输入:s = "()"
输出:true
思考:用一个栈来存储,左括号就入栈,右括号就出栈。出栈如果不是对应的符号,则false。如果最后栈为空,则返回true。
class Solution {
public:
bool isValid(string s) {
if (s.size() % 2 != 0) return false;
stack<int> 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();
}
};
- 时间复杂度: O(n)
- 空间复杂度: O(n)
第一种情况:已经遍历完了字符串,但是栈不为空,说明有相应的左括号没有右括号来匹配,所以return false
第二种情况:遍历字符串匹配的过程中,发现栈里没有要匹配的字符。所以return false
第三种情况:遍历字符串匹配的过程中,栈已经为空了,没有匹配的字符了,说明右括号没有找到对应的左括号return false
那么什么时候说明左括号和右括号全都匹配了呢,就是字符串遍历完之后,栈是空的,就说明全都匹配了。
1047. 删除字符串中的所有相邻重复项
https://leetcode.cn/problems/remove-all-adjacent-duplicates-in-string/
给出由小写字母组成的字符串 S
,重复项删除操作会选择两个相邻且相同的字母,并删除它们。
在 S 上反复执行重复项删除操作,直到无法继续删除。
在完成所有重复项删除操作后返回最终的字符串。答案保证唯一。
示例:
输入:"abbaca"
输出:"ca"
思考:删除相邻的重复项。双指针不太好操作,可以利用栈的特性,进行删除。
1、利用栈进行重复元素去除。2、遍历得到栈中的元素,此时是反序的。3、再逆序一下。
class Solution {
public:
string removeDuplicates(string s) {
stack<char> st;
for (char si : s) {
if (!st.empty() && si == st.top()) {
st.pop();
} else {
st.push(si);
}
}
string result = "";
while(!st.empty()) {
result += st.top();
st.pop();
}
reverse(result.begin(), result.end());
return result;
}
};
- 时间复杂度: O(n)
- 空间复杂度: O(n)
直接使用string 当做栈也行
class Solution {
public:
string removeDuplicates(string s) {
string result;
for (char si : s) {
if (!result.empty() && si == result.back()) {
result.pop_back();
}else {
result.push_back(si);
}
}
return result;
}
};
- 时间复杂度: O(n)
- 空间复杂度: O(1),返回值不计空间复杂度
递归的实现就是:每一次递归调用都会把函数的局部变量、参数值和返回地址等压入调用栈中,然后递归返回的时候,从栈顶弹出上一次递归的各项参数,所以这就是递归为什么可以返回上一层位置的原因。
相信大家应该遇到过一种错误就是栈溢出,系统输出的异常是Segmentation fault
(当然不是所有的Segmentation fault
都是栈溢出导致的) ,如果你使用了递归,就要想一想是不是无限递归了,那么系统调用栈就会溢出。
而且在企业项目开发中,尽量不要使用递归!在项目比较大的时候,由于参数多,全局变量等等,使用递归很容易判断不充分return的条件,非常容易无限递归(或者递归层级过深),造成栈溢出错误(这种问题还不好排查!)
150. 逆波兰表达式求值
https://leetcode.cn/problems/evaluate-reverse-polish-notation/
给你一个字符串数组 tokens
,表示一个根据 逆波兰表示法 表示的算术表达式。
示例 1:
输入:tokens = ["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 nums1 = st.top();
st.pop();
long long nums2 = st.top();
st.pop();
if (tokens[i] == "+") st.push(nums2 + nums1);
if (tokens[i] == "-") st.push(nums2 - nums1);
if (tokens[i] == "*") st.push(nums2 * nums1);
if (tokens[i] == "/") st.push(nums2 / nums1);
}else {
st.push(stoll(tokens[i]));
}
}
int result = st.top();
st.pop();
return result;
}
};
- 时间复杂度: O(n)
- 空间复杂度: O(n)
思路不难,但是代码细节比较容易出错。
1、应该用双引号:“”
2、容易打错字符,搞错括号
复盘总结
个人反思
主要把栈的相关题刷了一下。
栈对于成对的符号检测,逆波兰表达式运算应用广泛。
栈一个特征点就是能知道遍历的上一个元素的值,用于后序比较。