前言
欢迎大家积极在评论区留言发表自己的看法,知无不言,言无不尽,养成每天刷题的习惯,也可以自己发布优质的解题报告,供社区一同鉴赏,吸引一波自己的核心粉丝。
今天是六月集训第十四天:栈🔥🔥
一、练习题目
剑指 Offer 31. 栈的压入、弹出序列
946. 验证栈序列
856. 括号的分数
1190. 反转每对括号间的子串
二、算法思路
-
1、剑指 Offer 31. 栈的压入、弹出序列:这是一道很经典的栈模拟题,考数据结构的时候经常会手推。这题设计一个辅助栈来模拟一下是否能得到弹出的结果。🔥🔥
-
2、946. 验证栈序列:同上。🔥🔥
-
3、856. 括号的分数:括号匹配的类型可以用栈,递归,dfs等。这里我用栈来模拟一下。画个图🔥🔥
-
4、1190. 反转每对括号间的子串:简单题,利用栈来找括号,然后将括号内的字符串翻转即可。🔥
三、源码剖析
// 剑指 Offer 31. 栈的压入、弹出序列
// 946. 验证栈序列
class Solution {
public:
bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
stack<int> stk; //(1)
int j = 0;
for(int i = 0; i < pushed.size(); ++i) {
stk.push(pushed[i]); //(2)
while(!stk.empty() && stk.top() == popped[j]) { //(3)
stk.pop();
j++;
}
}
return stk.empty(); //(4)
}
};
- 1、建立辅助栈;
- 2、遍历所有的pushed元素,模拟入栈的情况;
- 3、如果辅助栈的栈顶元素与popped中元素相等,模拟出栈操作;
- 4、判断辅助栈的状态。为空,返回true;不为空,返回false,因为如果能弹出的辅助栈一定被清空。
// 856. 括号的分数
class Solution {
public:
int scoreOfParentheses(string s) {
stack<int> stk;
for(char c: s) {
if(c == '(') { //(1)
stk.push(0);
} else {
if(stk.top() == 0) { //(2)
stk.pop();
stk.push(1);
} else { //(3)
int cnt = 0;
while (stk.top())
{
cnt += stk.top();
stk.pop();
}
stk.pop();
stk.push(cnt * 2);
}
}
}
int ans = 0;
while (!stk.empty()) //(4)
{
ans += stk.top();
stk.pop();
}
return ans;
}
};
- 1、字符其实有指定的ASCII码值,我们直接用固定的数字模拟,碰到左括号用0代替;
- 2、碰到右括号了,同时栈顶是0表示左括号,根据题意
()
是要转换成1分的,弹出左括号,压入1; - 3、碰到右括号,但是栈顶不是0,说明是
(ABC……)
这么个情况,我们需要用一个计数器cnt累加他们,根据题意累加完后cnt*2,同时弹出左括号,压入cnt; - 4、最后栈内只有分数了,就是累加的情况。
// 1190. 反转每对括号间的子串
class Solution {
public:
string reverseParentheses(string s) {
stack<int> stk;
for(int i = 0; i < s.length(); ++i) {
if(s[i] == '(') {
stk.push(i); //(1)
} else {
if(s[i] == ')') { //(2)
int l = stk.top() + 1;
int r = i - 1;
stk.pop();
while(l <= r) {
char tmp = s[l];
s[l++] = s[r];
s[r--] = tmp;
}
}
}
}
string ans;
for(auto c : s) {
if(c != '(' && c != ')') { //(3)
ans += c;
}
}
return ans;
}
};
- 1、左括号的话吧下标入栈;
- 2、碰到右括号,栈顶肯定是一个左括号,如果中间有字符串那么从栈顶加1的位置开始就是字符串的头,同时当前位置减1肯定是字符串的尾,利用这双指针的移动进行字符的翻转;
- 3、最后把字符取出来就是答案了。