LeetCode-栈与队列

1. 225. 用队列实现栈

用一个队列就可以实现栈
取元素时要把队列尾元素取出(最后进入队列的元素)
把前n-1个元素放到队列尾并弹出,这样队列的头部就是最后进入队列的元素了,取出他即可

class MyStack {
private:
    queue<int> que;
public:
    MyStack() {

    }
    void push(int x) {
        que.push(x);
    }
    int pop() {
        int n = que.size() - 1;
        while(n--){
            que.push(que.front());
            que.pop();
        }
        int res = que.front();
        que.pop();
        return res;
    }
    int top() {
        return que.back();
    }
    bool empty() {
        return que.empty();
    }
};

2. 面试题 03.04. 化栈为队

需要把栈最里面的元素取出来,不能像队列那样操作了,那样最里面的元素依旧在最里面
用两个栈,把1栈所有元素取出放到2栈中,此时2栈中所有元素出栈顺序为队列顺序,直接取出元素即可
注意只有当栈2位空时才补充元素到栈2,否则会影响出栈顺序

class MyQueue {
private:
    stack<int> stk1;
    stack<int> stk2;
public:
    MyQueue() {

    }
    void push(int x) {
        stk1.push(x);
    }
    int pop() {
        if(stk2.empty()){
            while(!stk1.empty()){
                stk2.push(stk1.top());
                stk1.pop();
            }
        }
        int res = stk2.top();
        stk2.pop();
        return res;
    }
    int peek() {
        if(stk2.empty()){
            while(!stk1.empty()){
                stk2.push(stk1.top());
                stk1.pop();
            }
        }
        return stk2.top();
    }
    bool empty() {
        return stk1.empty() && stk2.empty();
    }
};

3. 1021. 删除最外层的括号

方法一:
相当于单调栈,栈中只放左括号,遇到右括号弹出一个左括号,用是否栈空判断括号是否完全
要在添加之前,删除之后,判断站是否为空,来判断是否为中间元素

string removeOuterParentheses(string S) {
        stack<char> stk;
        int start = 0;
        string res = "";
        for(int i = 0; i < S.size(); i++){
            if(S[i] == ')'){
                stk.pop();
            }
            if(!stk.empty()){
                res += S[i];
            }
            if(S[i] == '('){
                 stk.push('(');
            }
        }
        return res;
    }

方法二:
原理相同,改用变量记录左括号个数,节省空间

string removeOuterParentheses(string S) {
        stack<char> stk;
        int count = 0;
        string res = "";
        for(int i = 0; i < S.size(); i++){
            if(S[i] == ')'){
                count--;
            }
            if(count != 0){
                res += S[i];
            }
            if(S[i] == '('){
                count++;
            }
        }
        return res;
    }

4. 1047. 删除字符串中的所有相邻重复项

模拟栈节省空间,原地修改,指针指向当前最后一个元素,与前一个元素不相同就加入,相同就退格(删除),最后重新设定字符串大小
也可以新建立一个字符串,用push_back(),pop_back()模拟栈

string removeDuplicates(string S) {
        int index = 0;
        for(char c : S){
            if(index == 0 || S[index - 1] != c){
                S[index++] = c;
            }
            else{
                index--;
            }
        }
        S.resize(index);
        return S;
    }

5. 155. 最小栈

-1,1,1 当-1不退栈时,最小值永远是-1
方法一:
用辅助栈,辅助栈顶存放当前最小值,辅助栈与栈同时退栈
如-1,-1,-2,1辅助栈存放为,-1,-1,-2,-2
入栈时当前值小于辅助栈顶时更换元素
也可以用stack<int,pair<int,int>> 类型

class MinStack {
private:
    stack<int> stk_min;
    stack<int> stk;
public:
    void push(int x) {
        if(stk.empty()){
            stk_min.push(x);
        }
        else{
            stk_min.push(min(x,stk_min.top()));
        }
        stk.push(x);
    }
    void pop() {
        stk_min.pop();
        stk.pop();
    }
    int top() {
        return stk.top();
    }
    int getMin() {
        return stk_min.top();
    }
};

方法二:
只用一个栈,栈中储存与最小值的差值,min储存当前最小值
要用long储存,栈中元素最大为INT_MAX - INT_MIN
top,元素为负数时,返回当前最小值(此时差值用于计算出上一个min),为负数时当前min就是他的值
push、pop,当元素为负数时更换最小值

class MinStack {
private:
    stack<long> stk;
    long min;
public:
    void push(int x) {
        if(stk.empty()){
            min = x;
        }
        stk.push(x - min);
        if(x < min){
            min = x;
        }
    }
    void pop() {
        if(stk.top() < 0){
            min -= stk.top();
        }
        stk.pop();
    }
    int top() {
        if(stk.top() < 0) return min;
        return min + stk.top();
    }
    int getMin() {
        return min;
    }
};

6. 1019. 链表中的下一个更大节点

单调栈:用于找数组中第一个比他大的数据(单调递减栈,留在栈中的都是后来没有比他的数了)
栈中存放的是索引,因为只知道数据大小是没办法准确插入到相应位置的

vector<int> nextLargerNodes(ListNode* head) {
        stack<int> stk;
        int n = 0;
        vector<int> nums;
        while(head != nullptr){
            nums.push_back(head->val);
            head = head->next;
            n++;
        }
        vector<int> res(n,0);
        for(int i = 0; i < nums.size(); i++){
            while(!stk.empty() && nums[stk.top()] < nums[i]){
                res[stk.top()] = nums[i];
                stk.pop();
            }
            stk.push(i);
        }
        return res;
    }

本题优化,用res数组兼职nums和res数组的功能,因为只使用之前的数据且res数据记录答案后就不再使用了,所以边记录边比较同时可以直接覆盖
由于默认值没有设置,所以再遍历一遍栈,将栈中剩余元素置为0(剩余元素都是右边没有更大值了,即递减的)

vector<int> nextLargerNodes(ListNode* head) {
        stack<int> stk;
        int i = 0;
        vector<int> res;
        while(head != nullptr){
            while(!stk.empty() && res[stk.top()] < head->val){
                res[stk.top()] = head->val;
                stk.pop();
            }
            res.push_back(head->val);
            stk.push(i++);
            head = head->next;
        }
        while(!stk.empty()){
            res[stk.top()] = 0;
            stk.pop();
        }
        return res;
    }

收获与体会

  1. 一般可以用模拟栈的方式节省空间
  2. 找第一个比当前元素大/小的数就用单调栈做
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值