当前位置 博文首页 >  落禅的博客:栈和队列刷题集合

     落禅的博客:栈和队列刷题集合

    作者:[db:作者] 时间:2021-09-10 22:36

    栈刷题集合

    面试题 03.02. 栈的最小值

    请设计一个栈,除了常规栈支持的pop与push函数以外,还支持min函数,该函数返回栈元素中的最小值。执行push、pop和min操作的时间复杂度必须为O(1)。

    //示例:
    MinStack minStack = new MinStack();
    minStack.push(-2);
    minStack.push(0);
    minStack.push(-3);
    minStack.getMin();   --> 返回 -3.
    minStack.pop();
    minStack.top();      --> 返回 0.
    minStack.getMin();   --> 返回 -2.
    

    本题思路:首先栈的push,top,操作我们可以直接用stl库函数,最麻烦的是min函数,而且时间复杂度为O(1),这个思想非常重要,定义一个栈s1,专门用来存放栈中的元素,完成栈的push,pop工作,然后定义一个辅助栈,来存放最小值,使得每一个s1对应的栈顶元素都有对应的最小值

    class MinStack {
    
    public:
    
      /** initialize your data structure here. */
    
      //1.定义两个栈,第一个栈用来存储值
      //第二个栈用来寻找最小值
      stack<int>s1;
    
      stack<int>s2;
    
      MinStack() {
    ?    //先将s2初始化
    ?    s2.push(INT_MAX);
      }
    
      void push(int x) {
    
    ?    //为s1赋值
    
    ?    s1.push(x);
    
    ?    //每次找到栈顶元素和输入元素的较小值进行比较,使得s1的每个主站元素都有其对应的最小值
    
    ?    s2.push(min(s2.top(),x));
    
      }
    
      
    
      void pop() {
    
    ?    //s1执行pop操作
    
    ?    //与之对应的最小值也执行pop操作,让每个栈顶元素与最小值进行对应
    
    ?    s1.pop();
    
    ?    s2.pop();
      }
    
    
      int top() {
    ?    return s1.top();
      }
      
      
      int getMin() {
    ?    return s2.top();
      }
    };
    
    /**
    
     \* 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();
    
     */
    

    剑指 Offer 31. 栈的压入、弹出序列

    输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如,序列 {1,2,3,4,5} 是某栈的压栈序列,序列 {4,5,3,2,1} 是该压栈序列对应的一个弹出序列,但 {4,3,5,1,2} 就不可能是该压栈序列的弹出序列。

    示例 1:
    输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
    输出:true
    解释:我们可以按以下顺序执行:
    push(1), push(2), push(3), push(4), pop() -> 4,
    push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1
    
    
    示例 2:
    输入:pushed = [1,2,3,4,5], popped = [4,3,5,1,2]
    输出:false
    解释:1 不能在 2 之前弹出。
    

    思路:首先建立一个栈,我们将pushed中的元素进行入栈,判断栈中的top()和popped中的元素是否相等,如果相等那么就st.pop(),popped中的元素向后走一位,之后再将pushed中的下一个元素继续入栈;如果不相等就将push元素后移,循环结束条件为i<push.size(),此时pushed数组已经走到了结尾,最终只需要判断popped数组是否走到了结尾,要是两者都走到了结尾,就说明两者为栈的压入与弹出,不相等说明不是栈的压入与弹出

    class Solution {
    public:
        bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
            int i=0;
            int j=0;
            //建立一个栈
            stack<int>st;
            //循环结束条件:pushed数组遍历完
            while(i<pushed.size())
            {
            	//每次将pushed[i]进入栈中
                st.push(pushed[i]);
                //判断刚进入栈的元素,即栈顶元素是否与popped[j]相等,相等st.pop(),j++
                while(!st.empty()&&st.top()==popped[j])
                {
                    st.pop();
                    j++;
                }
                //直到st,top()与popped[j]不相等
                之后++i;
                i++;
            }
            //判断是否为栈的压入与弹出只需要判断popped数组是否走完了
            return j==popped.size();
    }
    };
    

    150. 逆波兰表达式求值

    根据 逆波兰表示法,求表达式的值。

    有效的算符包括 +、-、*、/ 。每个运算对象可以是整数,也可以是另一个逆波兰表达式。

    说明:

    整数除法只保留整数部分。
    给定逆波兰表达式总是有效的。换句话说,表达式总会得出有效数值且不存在除数为 0 的情况。

    示例 1:
    输入:tokens = ["2","1","+","3","*"]
    输出:9
    解释:该算式转化为常见的中缀算术表达式为:((2 + 1) * 3) = 9
    
    示例 2:
    输入:tokens = ["4","13","5","/","+"]
    输出:6
    解释:该算式转化为常见的中缀算术表达式为:(4 + (13 / 5)) = 6
    
    示例 3:
    输入:tokens = ["10","6","9","3","+","-11","*","/","*","17","+","5","+"]
    输出:22
    解释:
    该算式转化为常见的中缀算术表达式为:
      ((10 * (6 / ((9 + 3) * -11))) + 17) + 5
    = ((10 * (6 / (12 * -11))) + 17) + 5
    = ((10 * (6 / -132)) + 17) + 5
    = ((10 * 0) + 17) + 5
    = (0 + 17) + 5
    = 17 + 5
    = 22
    
    
    提示:
    1 <= tokens.length <= 104
    tokens[i] 要么是一个算符("+""-""*""/"),要么是一个在范围 [-200, 200] 内的整数
    
    逆波兰表达式:
    
    逆波兰表达式是一种后缀表达式,所谓后缀就是指算符写在后面。
    平常使用的算式则是一种中缀表达式,如 ( 1 + 2 ) * ( 3 + 4 ) 。
    该算式的逆波兰表达式写法为 ( ( 1 2 + ) ( 3 4 + ) * ) 。
    逆波兰表达式主要有以下两个优点:
    去掉括号后表达式无歧义,上式即便写成 1 2 + 3 4 + * 也可以依据次序计算出正确结果。
    适合用栈操作运算:遇到数字则入栈;遇到算符则取出栈顶两个数字进行计算,并将结果压入栈中。
    

    逆波兰表达式(后缀表达式)求解方法:建立一个栈,遇到数字就入栈,遇到运算符就取出栈顶的两个元素进行相应的运算,并且将运算结果压入栈中

    class Solution {
    
    public:
    
    //逆波兰表达式(后缀表达式)计算方法:遇到数字就入栈,遇到运算符就进行运算,运算完成后将结果再次返回到栈中,到最后返回栈顶元素即可
      void GetNumber(stack<int>&st,int&left,int&right)
      {
    ?    right=st.top();
    ?    st.pop();
    ?    left=st.top();
    ?    st.pop();
      }
    
    
      int evalRPN(vector<string>& tokens) {
    ?    stack<int>st;
    ?    //auto自动变量遍历每一个数组内容赋值到str中去
    ?    for(auto &str :tokens)
    ?    {
    ?      int left,right;
    ?      //str.back():返回末尾最后一位字符,用于判断它是什么符号
    
    下一篇:没有了