算法-栈,队列

Posted chendaniu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了算法-栈,队列相关的知识,希望对你有一定的参考价值。

常见的栈与队列算法题

1.使用队列实现栈

2.使用栈实现队列

3.包含最小值函数的栈

4.合法的出栈序列

5.简单计算器


1.队列实现栈

class MyStack {
public:
    /** Initialize your data structure here. */
    MyStack() {
        
    }
    
    /** Push element x onto stack. */
    void push(int x) {
        int len=data.size();
        data.push(x);
        while(len>0){
            data.push(data.front());
            data.pop();
            len--;
        }
    }
    
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        int res=data.front();
        data.pop();
        return res;
        
    }
    
    /** Get the top element. */
    int top() {
        return data.front();
    }
    
    /** Returns whether the stack is empty. */
    bool empty() {
        return data.empty();
    }
private:
    std::queue<int> data;
};

/**
 * Your MyStack object will be instantiated and called as such:
 * MyStack obj = new MyStack();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.top();
 * bool param_4 = obj.empty();
 */

主要是push函数的编写。x进队后,让之前的元素 一 一 出队再入队。


2.栈实现队列

class MyQueue {
public:
    /** Initialize your data structure here. */
    MyQueue() {
        
    }
    
    /** Push element x to the back of queue. */
    void push(int x) {
        while(s.size()){
            s_temp.push(s.top());
            s.pop();
        }
        s.push(x);
        while(s_temp.size()){
            s.push(s_temp.top());
            s_temp.pop();
        }
    }
    
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
        int res=s.top();
        s.pop();
        return res;
    }
    
    /** Get the front element. */
    int peek() {
        return s.top();
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {
        return s.empty();
    }
private:
    std::stack<int> s,s_temp;
};

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue obj = new MyQueue();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.peek();
 * bool param_4 = obj.empty();
 */

缺点是,入队所需时间太长,操作步数为2n步。其他为常数。

改进

class MyQueue {
public:
    /** Initialize your data structure here. */
    MyQueue() {
        
    }
    void transfer(){
        while(!in.empty()){
            out.push(in.top());
            in.pop();   
        }
    }
    /** Push element x to the back of queue. */
    void push(int x) {
        in.push(x);
    }
    
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
        int res=peek();
        out.pop();
        return res;    
    }
    
    /** Get the front element. */
    int peek() {
        if(out.size()==0)
            transfer();
        return out.top();
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {
        return (in.empty() && out.empty());
    }
private:
    std::stack<int> in,out;
};

/**
 * Your MyQueue object will be instantiated and called as such:
 * MyQueue obj = new MyQueue();
 * obj.push(x);
 * int param_2 = obj.pop();
 * int param_3 = obj.peek();
 * bool param_4 = obj.empty();
 */

pop和peek平均都为n/2步,总步数n步。略微简化了一些。


3.最小值栈

设计一个支持 push,pop,top 操作,并能在常数时间内检索到最小元素的栈。

  • push(x) -- 将元素 x 推入栈中。
  • pop() -- 删除栈顶的元素。
  • top() -- 获取栈顶元素。
  • getMin() -- 检索栈中的最小元素。
class MinStack {
public:
    /** initialize your data structure here. */
    MinStack() {
        
    }
    
    void push(int x) {
        s.push(x); 
        if(sMin.empty() || x <= sMin.top()){
            sMin.push(x);
        }
    }
    
    void pop() {
        if(s.top()==sMin.top()){
            s.pop();
            sMin.pop();
        }else{
            s.pop();
        }
    }
    
    int top() {
        return s.top();
    }
    
    int getMin() {
        return sMin.top();
    }
private:
    std::stack<int> s,sMin;
};

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(x);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.getMin();
 */

用另一个栈sMin记录最小值。空间复杂度O(n).


 

4.合法的出栈序列

class Solution {
public:
    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
        stack<int> s;
        int len=pushed.size();
        int i=0,j=0;
        while(i<len){
            s.push(pushed[i++]);
            while(!s.empty()){
                if(s.top()==popped[j]){
                    s.pop();
                    j++;
                }else{
                    break;
                }
            }
            
        }
        return s.empty();
    }
};

借助一个栈s,模拟进出栈顺序。遍历pushed数组,先将元素进栈。然后再开一个出栈循环,若栈不空,将栈顶与popped数组元素比较,相同则出栈,继续下一个循环;不同则跳出出栈循环,继续外面的进栈操作。最后返回是否栈空。以上应该是最为清晰的思路了,之前我也写过两个,一个暴力法判断,时间复杂度较高,逻辑也很复杂;另一个也是模拟进出栈,但是思路太乱,代码逻辑冗余混乱,简单来说就是模拟的不够真实,反而导致自己思路不畅。


5.简单计算器

实现一个基本的计算器来计算一个简单的字符串表达式的值。

字符串表达式可以包含左括号 ( ,右括号 ),加号 + ,减号 -非负整数和空格

class Solution {
public:
    int calculate(string s) {
        int len = s.length();
        if (len == 0) return 0;//长度为0直接返回0
        int num1 = 0, num2 = 0;//存储运算数
        bool flag = false;//是否能进行运算
        stack<int> num;//数字栈
        stack<char> op;//运算符栈
        int temp = 0;//存储数字
        for (int i = 0; i < len; i++) {
            if (s[i] ==  ) continue;
            if (s[i] >= 0 && s[i] <= 9) {
                temp = temp * 10 + s[i] - 0;
                if (i + 1 == len || s[i + 1]<0 || s[i + 1]>9) {
                    num.push(temp);
                    temp = 0;//清0
                }else {
                    continue;//继续入栈求该数字
                }
            }else if (s[i] == () {
                flag = false;//设置无法运算
                continue;
            }else if (s[i] == + || s[i] == -) {
                op.push(s[i]);
                flag = true;//可以运算
                continue;
            }else if(s[i]==)){
                flag = true;//可以运算
            }

            if (flag && !op.empty()) {    //运算栈不为空才可以运算
                num2 = num.top(); num.pop();
                num1 = num.top(); num.pop();
                if (op.top() == +) {
                    num.push(num1 + num2);
                }
                else {
                    num.push(num1 - num2);
                }
            op.pop();//不要忘记出栈
            }
        }
        return num.top();
    }
};

 重点在于flag,表示是否能进行运算。数字入数字栈,运算符入运算符栈,且设flag=true。左括号使得flag=false,右括号使得false=true。flag为true且运算栈不为空则进行运算,运算完不要忘记出栈

 

以上是关于算法-栈,队列的主要内容,如果未能解决你的问题,请参考以下文章

代码随想录算法训练营第10天 | ● 理论基础 ● 232.用栈实现队列 ● 225. 用队列实现栈

算法:用双队列实现栈

⭐算法入门⭐《栈 和 队列》简单02 —— LeetCode 225. 用队列实现栈

考研数据结构与算法栈和队列

算法笔记-数组实现栈,队列

[算法] leetcode栈与队列相关题目详解