【刷题记录】stack queue的题目练习(上)

简介: 【刷题记录】stack queue的题目练习(上)

1. 最小栈


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

题干:

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

实现 MinStack 类:


  • MinStack() 初始化堆栈对象。
  • void push(int val) 将元素val推入堆栈。
  • void pop() 删除堆栈顶部的元素。
  • int top() 获取堆栈顶部的元素。
  • int getMin() 获取堆栈中的最小元素。


示例:

输入:

[“MinStack”,“push”,“push”,“push”,“getMin”,“pop”,“top”,“getMin”]

[[],[-2],[0],[-3],[],[],[],[]]


输出:

[null,null,null,null,-3,null,0,-2]


解释:

MinStack minStack = new MinStack();

minStack.push(-2);

minStack.push(0);

minStack.push(-3);

minStack.getMin(); --> 返回 -3.

minStack.pop();

minStack.top(); --> 返回 0.

minStack.getMin(); --> 返回 -2.


题目分析:


为了能够在O(1)的时间复杂度内找到当前栈中的最小值,我们能想到使用两个栈,一个栈正常存储数据(数据栈),另一个栈存储当前栈中的最小值(最小栈),这样最小值就能直接找到。


每次push数据的时候数据站正常push,最小栈判断在push之前的最小值与当前值的大小,如果push数据小于最小栈的top,那么最小栈就push当前值,否则就push栈顶值。

4277c1a91da1ab8486bdaae8c39fb1be.png

实际上,如果入栈的数据大多数都大于当前最小值时,最小栈中就会出现很多相同且连续的数,这样对于空间是很大的浪费,所以,我们可以考虑修改最小栈的入栈规则,只有当新入栈的数据小于当前最小值时才入最小栈,这样最小栈中的数据就不会出现这种冗余。


[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4feFqUnf-1682496626758)(null)]


代码实现:

//解法一:
class MinStack {
public:
    MinStack() {//这里默认构造函数就不用实现了,因为在这里成员变量会走初始化列表,在初始化列表这里会自动调用成员变量类型的默认构造函数
    }    
    void push(int val) {
        _st.push(val);
        if(_minst.empty() || val <= _minst.top())
        {
            _minst.push(val);
        }
    }    
    void pop() {
        if(_st.top() == _minst.top())
        {
            _minst.pop();
        }
        _st.pop();
    }   
    int top() {
        return _st.top();
    }
    int getMin() {
        return _minst.top();
    }
    stack<int> _st;
    stack<int> _minst;
};


976b8fb5f359962e59e627da9b98387b.png


2. 逆波兰表达式


题目链接:150. 逆波兰表达式求值 - 力扣(LeetCode)

题干:

给你一个字符串数组 tokens ,表示一个根据 逆波兰表示法 表示的算术表达式。

请你计算该表达式。返回一个表示表达式值的整数。

注意:

  • 有效的算符为 '+'、'-'、'*' 和 '/' 。
  • 每个操作数(运算对象)都可以是一个整数或者另一个表达式。
  • 两个整数之间的除法总是 向零截断 。
  • 表达式中不含除零运算。
  • 输入是一个根据逆波兰表示法表示的算术表达式。
  • 答案及所有中间计算结果可以用 32 位 整数表示。

示例 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


题目分析:

对于逆波兰表达式的计算,我们按照顺序遍历的方式,找到第一个运算符,然后将前面两个操作数拿出来运算即可,按照这种方式,我们可以想到用栈来存放数据,遇到操作符就pop出两个元素用于运算

155cd411fdc487faffab1324d0cd7877.png

代码实现:

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> st;
        for(auto& str : tokens)
        {
            if(str == "+" || str == "-" || str == "*" || str == "/")//遇到运算符
            {
                //拿到左右两个操作数
                int right = st.top();
                st.pop();
                int left = st.top();
                st.pop();
                switch(str[0])//判断是什么运算,然后将运算结果入栈
                {
                    case '+':
                        st.push(left + right);
                        break;
                    case '-':
                        st.push(left - right);
                        break;
                    case '*':
                        st.push(left * right);
                        break;
                    case '/':
                        st.push(left / right);
                        break;
                }
            }
            else//遇到数字
            {
                st.push(stoi(str));
            }
        }
        return st.top();
    }
};


12bc65f8f2a04a368cb5bd3b9708f0e7.png

拓展知识:中缀表达式和后缀表达式

表达式时由操作数和操作符组成的,我们一般见到的表达式通常是把操作符放在两个操作数之间的,这种把操作符放在中间的表达式叫做中缀表达式,这种表达式对人类很友好,但是对计算机不太友好。波兰数学家Jan Lukasiewicz提出了另一种数学表示法,它有两种表示形式:把运算符写在操作数之前,称为波兰表达式(Polish Expression)或前缀表达式(Prefix Expression),如+AB;把运算符写在操作数之后,称为逆波兰表达式(Reverse Polish Expression)或后缀表达式(Suffix Expression),如AB+。在上题中提到的逆波兰表达式就是后缀表达式


这里给出中缀转后缀的算法思路:


  1. 创建栈
  1. 从左向右顺序获取中缀表达式
  • 数字直接输出
  • 运算符
  • 情况一:遇到左括号直接入栈,遇到右括号将栈中左括号之后入栈的运算符全部弹栈输出,同时左括号出栈但是不输出。
  • 情况二:遇到乘号和除号直接入栈,直到遇到优先级比它更低的运算符,依次弹栈。
  • 情况三:遇到加号和减号,如果此时栈空,则直接入栈,否则,将栈中优先级高的运算符依次弹栈(注意:加号和减号属于同一个优先级,所以也依次弹栈)直到栈空或则遇到左括号为止,停止弹栈。(因为左括号要匹配右括号时才弹出)。
  • 情况四:获取完后,将栈中剩余的运算符号依次弹栈输出
相关文章
|
4月前
剑指 Offer 35:复杂链表的复制
剑指 Offer 35:复杂链表的复制
24 0
|
5月前
剑指 Offer 30. 包含min函数的栈
剑指 Offer 30. 包含min函数的栈
22 0
|
4月前
剑指 Offer 30:包含min函数的栈
剑指 Offer 30:包含min函数的栈
24 0
|
5月前
|
存储
LeetCode155|剑指 Offer 30. 包含 min 函数的栈
调用 min、push 及 pop 的时间复杂度都是 O(1) 因此实现一个能够得到栈的最小元素的 min 函数,我们就不能使用for等循环去查找,直接去排序大可不必,所以我们可以通过创建另一个栈,专门去存储每次比较的最小值。
18 0
|
5月前
|
存储 C++
LeetCode138|剑指 Offer 35. 复杂链表的复制
复制,就需要和原链表的地址不同,不能引用原地址,因此你需要开辟新的空间。 正常情况下,你只需要遍历下面,但现在是复杂链表,random指向任意的节点,所以 如果你只是遍历多次,你可能遇到指向的节点,在遍历时候还没有创建,或者创建成功了,每次去查找它,让时间复杂度何其复杂,所以我们要存储节点
10 0
|
7月前
|
容器
【刷题记录】stack queue的题目练习(下)
【刷题记录】stack queue的题目练习(下)
|
12月前
|
C++
【学习笔记】C++ stack和queue题目练习
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。 实现 MinStack 类: MinStack(),初始化堆栈对象。 void push(int val) 将元素val推入堆栈。 void pop() 删除堆栈顶部的元素。 int top() 获取堆栈顶部的元素。 int getMin() 获取堆栈中的最小元素。
115 0
|
存储
图解LeetCode——剑指 Offer 30. 包含min函数的栈
图解LeetCode——剑指 Offer 30. 包含min函数的栈
60 0