栈及其leetcode的一些练习

1. 简要介绍

栈就像叠盘子,先进后出;队列就像排队,先进先出。栈既可以用数组来实现,也可以用链表来实现。用数组实现的栈,叫作顺序栈,用链表实现的栈,叫作链式栈

常用操作:

(1)数据存取:

  • push(elem); //向栈顶添加元素
  • pop(); //从栈顶移除第一个元素
  • top(); //返回栈顶元素

(2)大小操作:

  • empty(); //判断堆栈是否为空
  • size(); //返回栈的大小

2. Leetcode练习题

leetcode上关于栈的题目:20,155,232,844,224,682,496.

2.1 20.有效的括号

题目链接:20. 有效的括号 - 力扣(LeetCode)

分析:遇到能匹配的括号就pop。

class Solution {
public:
    bool isValid(string s) {
        vector<char> v;
        //如果是奇数一定是无效字符串
        if(s.length() % 2 == 1) return false;
        //最简单的思路
        for(char c : s) {            
            if(c == '(' || c == '[' || c == '{') {
                v.push_back(c);
            }
            if(v.empty()) return false; //都没有左括号,直接返回false
            if(c == ')') {
                if(v.back() != '(') return false;
                v.pop_back();
            }
            else if (c == ']') {
                if(v.back() != '[') return false;
                v.pop_back();
            }
            //如果用else if就不会出错,如果用else就会出错
            else if (c == '}'){
                if(v.back() != '{') return false;
                v.pop_back();
            }
        }
        return v.empty() ? true : false; 
    }
};

2.2 155.最小栈

题目链接:155. 最小栈 - 力扣(LeetCode)

分析:我觉得目前看到的最好且最简洁的一个思路就是用pair来存储数据,每次加入新的数据的时候都进行一次比较,让栈顶元素的second值为最小值,直接可以返回最小值。

class MinStack {
public:
    MinStack() {

    }

    void push(int x) {
        if(st.empty()) {
            st.push({x, x});
        } else {
            st.push({x, min(x, st.top().second)});
        }
    }
    //pop的时候在非空栈上操作
    void pop() {
        st.pop();
    }

    int top() {
        return st.top().first;
    }

    int getMin() {
        return st.top().second;
    }
private:
    // 用一个pair来存储,第一个数存储值,第二个数存储stack中最小的数,
    // 每次加入新的数的时候进行一次比较,也就是O(1)
    stack <pair<int, int>> st; 
};

2.3 232.用栈实现队列

题目链接:232. 用栈实现队列 - 力扣(LeetCode)

分析:用两个栈实现队列,画个图就能很好理解了,我觉得还是画图最方便。

class MyQueue {
public:
//栈的操作:push pop top 
    stack<int> stIn;
    stack<int> stOut;
    MyQueue() {

    }

    void push(int x) {
        stIn.push(x);
    }

    int pop() {
        if(stOut.empty()) {
            while(! stIn.empty()) {
                stOut.push(stIn.top());
                stIn.pop();
            }
        }
        int ret = stOut.top();
        stOut.pop();
        return ret;
    }

    int peek() {
        int ret =  this->pop(); //直接用已经定义好的
        stOut.push(ret); //记得push回去
        return ret;
    }

    bool empty() {
        return stIn.empty() && stOut.empty();
    }
};

2.4 844.比较含退格的字符串

题目链接:844. 比较含退格的字符串 - 力扣(LeetCode)

分析:因为字符串是否相等可以直接用==,所以选择用两个string来存储处理后的数据,每次加入字符串中的字符时进行一次比较,有退格就pop,没有就push。

class Solution {
public:
    bool backspaceCompare(string s, string t) {
        string stS, stT;
        for(auto c : s) {
            if(c != '#') {
                stS.push_back(c);
            } 
            // 必须加上这个判断,否则会出错
            else if(! stS.empty()) {
                stS.pop_back();
            }
        }

        for(auto c : t) {
            if(c != '#') {
                stT.push_back(c);
            } else if(! stT.empty()) {
                stT.pop_back();
            }
        }
        return stS == stT;  //直接用两个string的比较作为返回
    }
};

2.5 224.基本计算器

题目链接:224. 基本计算器 - 力扣(LeetCode)

分析:用的是括号展开+栈的做法,扫描一遍就可以了,时间复杂度是O(n)。

class Solution {
public:
    int calculate(string s) {
        stack<int> ops;
        ops.push(1);
        int i = 0, n = s.length(), ret = 0, sign = 1;
        while(i < n) {
            if(s[i] == ' ') {
                i++;
            } else if(s[i] == '+') {
                sign = ops.top();
                i++;
            } else if(s[i] == '-') {
                sign = -ops.top();
                i++;
            } else if(s[i] == '(') {
                ops.push(sign);
                i++;
            } else if(s[i] == ')') {
                ops.pop(); //有push就有pop,这是相对的
                i++;
            } else {
                long num = 0;
                //获取大于10的数字,保存为num
                while(i < n && s[i] >= '0' && s[i] <= '9') {
                    num = num * 10 + s[i] - '0'; //ascall码,所以要-'0'
                    i++; 
                }
                ret += num * sign;
            }
        }
        return ret;
    }
};

2.6 682.棒球比赛

题目链接:682. 棒球比赛 - 力扣(LeetCode)

分析:用一个vector来存储转化后的分数,每次加入的时候进行一次判断,并直接进行总分的计算。因为最后返回的结果是int,输入是string,所以用到了stoi()函数,stoi的参数是const string;是C++的字符处理函数,把数字字符串转换成int输出。

class Solution {
public:
    int calPoints(vector<string>& operations) {
        int ret = 0; //存储最终的计算结果
        vector<int> points; //用数组存储每次的分数
        for(auto &ops: operations) {
            int n = points.size();
            // cout << ops<< endl;
            // 必须用ops[0]才可以
            switch(ops[0]) {
            case '+':
                ret += points[n - 1] + points[n - 2];
                points.push_back(points[n - 1] + points[n - 2]);
                break;
            case 'D':
                ret += points[n-1] * 2;
                points.push_back(points[n-1] * 2);
                break;
            case 'C':
                ret -= points[n-1];
                points.pop_back();
                break;
            default:
            //stoi()的参数是const string;是C++的字符处理函数,把数字字符串转换成int输出
                ret += stoi(ops);
                points.push_back(stoi(ops));
                break;
            }
        }
        return ret;

    }
};

2.7 496.下一个更大元素 I

题目链接:496. 下一个更大元素 I - 力扣(LeetCode)

分析:用一个unordered_map存储nums2中的greater number,然后遍历nums1就可以得到结果。这样时间复杂度就是 O(nums1.length + nums2.length)。

看到了这篇题解,我觉得总结得非常好:单调栈解决 Next Greater Number 一类问题 - 下一个更大元素 I - 力扣(LeetCode)

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {
        int n = nums1.size(), m = nums2.size();
        unordered_map<int, int> res;
        stack<int> s;
        //倒着入栈,也就是正着出栈
        for(int i = m - 1; i >= 0; i--) {
            while(! s.empty() && s.top() <= nums2[i]) {
                s.pop();
            }
            res[nums2[i]] = s.empty() ? -1 : s.top();
            s.push(nums2[i]);
        }
        //查完nums2中的greater num之后,对nums1进行处理,时间复杂度为 O(nums1.length + nums2.length)
        vector<int> res1(n); 
        for(int i = n - 1; i >= 0; i--) {
            res1[i] = res[nums1[i]];
        }
        return res1;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值