栈基础知识
- 先入后出
- 可以处理具有完全包含关系的问题
经典的栈实现方法
class Stack{
public:
Stack(){}
void push(int x){
data.push_back(x);
return;
}
void pop(){
if(empty()) return;
data.pop_back();
}
bool empty(){
return data.size() == 0;
}
int size(){
return data.size();
}
void output(){
cout << "=====" << endl;
for(int i = data.size() - 1; i >= 0; i--){
cout << "" << data[i] <<endl;
}
cout << "=====" << endl;
}
private:
vector<int> data;
};
int main(){
Stack s;
string op;
int val;
while(cin >> op){
if(op == "push"){
cin >> val;
s.push(val);
}else if(op == "pop"){
s.pop();
}else if(op == "size"){
cout << "size: " << s.size() << endl;
}else if(op == "output"){
s.output();
}
}
}
栈的典型应用场景
场景一:操作系统中的线程栈
场景二:表达式求值
经典面试题 - 栈的基本操作
03.04.化栈为队
- 设置两个栈 s1,s2
- 第二个栈可以实现对第一个栈内的反序
- 入队列永远从s2入
- 出队列永远从s1出,如果s1空了,就将s2的元素反序入s1
class MyQueue {
public:
stack<int> s1,s2;
MyQueue() {}
void push(int x) {
s2.push(x);
return;
}
void transfer(){
if(!s1.empty()) return;
while(!s2.empty()){
s1.push(s2.top());
s2.pop();
}
return;
}
int pop() {
transfer();
int ret = s1.top();
s1.pop();
return ret;
}
int peek() {
transfer();
return s1.top();
}
bool empty() {
return s1.empty() && s2.empty();
}
};
682.棒球比赛
class Solution {
public:
int calPoints(vector<string>& ops) {
stack<int> s;
for(int i = 0; i < ops.size(); i++){
if(ops[i] == "+"){
int a = s.top(); s.pop();
int b = s.top();
s.push(a), s.push(a + b);
}else if(ops[i] == "D"){
s.push(2 * s.top());
}else if(ops[i] == "C"){
s.pop();
}else{
s.push(atoi(ops[i].c_str()));
}
}
int sum = 0;
while (!s.empty()){
sum += s.top();
s.pop();
}
return sum;
}
};
844.比较退格的字符串
class Solution {
public:
void transform(string S, stack<char> &s){
for(int i = 0 ; i < S.size(); i++){
if(S[i] == '#' && !s.empty()) s.pop();
else if(S[i] != '#') s.push(S[i]);
}
return;
}
bool backspaceCompare(string S, string T) {
stack<char> s;
stack<char> t;
transform(S, s);
transform(T, t);
if(s.size() - t.size()) return false;
while(!s.empty()){
if(s.top() != t.top()) return false;
s.pop();
t.pop();
}
return true;
}
};
946.验证栈序列
class Solution {
public:
bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
stack<int> s;
for(int i = 0, j = 0; i < popped.size(); i++){
while(j < pushed.size() && (s.empty() || s.top() != popped[i])){
s.push(pushed[j]);
j += 1;
}
if(s.top() != popped[i]) return false;
s.pop();
}
return true;
}
};
经典面试题-栈结构扩展应用
20.有效的括号
class Solution {
public:
bool isValid(string s) {
stack<char> ss;
for(int i = 0; i < s.size(); i++){
switch(s[i]){
case '(':
case '[':
case '{': ss.push(s[i]); break;
case ')': if(ss.empty() || ss.top() != '(') return false; ss.pop(); break;
case ']': if(ss.empty() || ss.top() != '[') return false; ss.pop(); break;
case '}': if(ss.empty() || ss.top() != '{') return false; ss.pop(); break;
}
}
return ss.empty();
}
};
1021.删除最外层的括号
- 遇上左括号加1,遇上右括号减1
- 直到0的时候即为分界点
class Solution {
public:
string removeOuterParentheses(string s) {
string ret;
for(int i = 0, pre = 0, cnt = 0; i < s.size(); i++){
if(s[i] == '(') cnt += 1;
else cnt -= 1;
if(cnt != 0) continue;
ret += s.substr(pre + 1, i - pre -1);
pre = i + 1;
}
return ret;
}
};
145.二叉树的后续遍历
- 前续遍历:根 左 右
- 中续遍历:左 根 右
- 后续遍历:左 右 根
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
if(root == nullptr) return vector<int>();
vector<int> ans;
stack<TreeNode *> s1;
stack<int> s2;
s1.push(root);
s2.push(0);
while(!s1.empty()){
int status = s2.top();
s2.pop();
switch(status){
case 0: {
s2.push(1);
if(s1.top()->left != nullptr){
s1.push(s1.top() -> left);
s2.push(0);
}
}break;
case 1:{
s2.push(2);
if(s1.top()->right != nullptr){
s1.push(s1.top() -> right);
s2.push(0);
}
}break;
case 2:{
ans.push_back(s1.top()->val);
s1.pop();
}break;
}
}
return ans;
}
};
331.验证二叉树的前序序列化
- x ## 可以缩略为 #
- 最后所有内容只要可以缩略为#,即为二叉树的前序序列化
class Solution {
public:
bool isValidSerialization(string preorder) {
vector<string> s;
for(int i = 0, j = 0; i < preorder.size(); i = j + 1){
j = i;
while(j < preorder.size() && preorder[j] != ',') ++j;
s.push_back(preorder.substr(i, j-i));
int last = s.size() - 1;
while(s.size() >= 3 && s[last] == "#" && s[last-1] == "#"){
s[last - 2] = "#";
s.pop_back();
s.pop_back();
last = s.size() -1;
}
if(s.size() == 2 && s[0] == "#" && s[1] == "#") return false;
}
return s.size() == 1 && s[0] == "#";
}
};
227.基本计算器ii
- 增加两个栈,一个为num存放数字,另一个为ops存放运算符
- 如果遇到比之前优先级小的运算符,先运算之前优先级大的结果弹出,再入栈新的运算符
- 最后清空栈,从运算符栈中依次计算,最后数字栈中留存的数字就是计算的结果
class Solution {
public:
int level(char c){
switch(c){
case '@': return -1;
case '+':
case '-': return 1;
case '*':
case '/': return 2;
}
return 0;
}
int calc(int a, char op, int b){
switch(op){
case '+': return a + b;
case '-': return a - b;
case '*': return a * b;
case '/': return a / b;
}
return 0;
}
int calculate(string s) {
stack<int> num;
stack<char> ops;
s += "@";
for (int i = 0, n = 0; i < s.size(); i++){
if(s[i] == ' ') continue;
if(level(s[i]) == 0){
n = n * 10 + (s[i] - '0');
continue;
}
num.push(n);
n = 0;
while(!ops.empty() && level(s[i]) <= level(ops.top())){
int b = num.top(); num.pop();
int a = num.top(); num.pop();
num.push(calc(a, ops.top(), b));
ops.pop();
}
ops.push(s[i]);
}
return num.top();
}
};
636.函数的独占时间
class Solution {
public:
vector<int> exclusiveTime(int n, vector<string>& logs) {
vector<int> ans(n);
stack<int> vID;
for(int i = 0, pre = 0; i < logs.size(); i++){
int pos1 = logs[i].find_first_of(":");
int pos2 = logs[i].find_last_of(":");
string id_str = logs[i].substr(0, pos1);
string status = logs[i].substr(pos1 + 1, pos2 - pos1 -1);
string time_str = logs[i].substr(pos2 + 1, logs[i].size());
int id = atoi(id_str.c_str());
int time_stamp = atoi(time_str.c_str());
if(status == "start"){
if(!vID.empty()){
ans[vID.top()] += time_stamp - pre;
}
pre = time_stamp;
vID.push(id);
} else {
ans[id] += time_stamp - pre + 1;
pre = time_stamp + 1;
vID.pop();
}
}
return ans;
}
};