20. 有效的括号
题目链接:有效的括号
视频讲解:栈的拿手好戏
栈的特殊结构,非常适合做对称匹配类的题目。
首先要弄清楚有几种不匹配的情况。其实总共就三种:
1、“( [ { } ] ( )” 左边括号多余;
2、“( [ { ] ] )” 括号类型不匹配;
3、“( [ { } ] ) ) )” 右边括号多余;
弄清楚这几种情况,那么怎么有效的运用栈呢?因为存在左括号就要有个有括号跟它匹配,在遍历字符串的时候,碰到左括号我们就可以往栈里放一个右括号,这样在字符串中寻找右括号时可以直接与栈中元素进行比较,不用过多的操作。
接下来就是讨论这几种情况了:
第一种情况:已经遍历完了,但是占中还有元素,说明没有足够的右括号与串中的左括号匹配,return false;
第二种情况:在遍历字符串时,没有与之匹配的字符,return false;
第三种情况:还没遍历完,栈已经空了,说明没有足够的左括号与右括号匹配,return false;
// 时间复杂度: O(n)
// 空间复杂度: O(n)
class Solution {
public:
bool isValid(string s) {
stack<char> st;
if (s.size() % 2 != 0) // 字符串为奇数可难听不满足条件
return false;
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() || s[i] != st.top()) // 没遍历完栈为空或字符串与栈顶元素不匹配
return false;
else st.pop(); // 匹配上了,弹出栈顶元素
}
return st.empty(); // 遍历完栈不为空 false,栈空 true
}
};
1047. 删除字符串中的所有相邻重复项
题目链接:删除字符串中的所有相邻重复项
视频讲解:栈的好戏还在继续
删除相邻重复项,其实就是匹配前后元素是否一样,用栈再好不过了。那么栈里该怎么放元素呢?
先遍历字符串中的元素,如果栈中没有与之相同的就把它放入栈中,如果栈中有就把从栈里删除该元素,直到遍历完,栈里的元素就是没有重复项的字符串了。但是,此时栈中元素与所求字符串顺序相反,就还得用个字符串把栈中元素倒序排列。其实,不需这么麻烦,我们可以直接定义一个字符串,让它发挥栈的功能。如前说述,当需要入栈时,此时对应的就是把该元素放到新定义的字符串串尾,需要删除时也是删除串尾,这样最后得出的字符串就是所需答案。
// 时间复杂度: O(n)
// 空间复杂度: O(n)
class Solution {
public:
string removeDuplicates(string s) {
string st;
for (auto i : s)
{
if (st.empty() || i != st.back())
{
st.push_back(i);
}
else st.pop_back();
}
return st;
}
};
150. 逆波兰表达式求值
题目链接:逆波兰表达式求值
视频讲解:栈的最后表演!
首先要明白逆波兰表达式,其实它就是二叉树中的后续遍历。把运算符作为中间节点,按照后续遍历的规则画出一个二叉树。但我们没必要用二叉树解决问题。只需要一个栈,遍历字符串时,遇到数字就放入栈中,遇到运算符,就把栈顶两个元素用该运算符计算,得到的答案继续入栈中,直到栈里只剩一个元素,就是所求的答案。
注意:字符串类型转成整型
// 时间复杂度: O(n)
// 空间复杂度: O(n)
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 n1 = st.top();
st.pop();
long long n2 = st.top();
st.pop();
if (tokens[i] == "+")
st.push(n1 + n2);
if (tokens[i] == "-")
st.push(n2 - n1);
if (tokens[i] == "*")
st.push(n1 * n2);
if (tokens[i] == "/")
st.push(n2 / n1);
}
else
{
st.push(stoll(tokens[i]));
}
}
int res = st.top();
st.pop();
return res;
}
};