当前位置: 首页 > article >正文

数据结构之栈和队列——LeetCode:150. 逆波兰表达式求值,224. 基本计算器,232. 用栈实现队列

150. 逆波兰表达式求值

题述

150. 逆波兰表达式求值

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

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

注意:

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

运行代码

class Solution {
public:
    int evalRPN(vector<string>& tokens) {
        stack<int> stk;
        int n = tokens.size();
        for (int i = 0; i < n; i++) {
            string& token = tokens[i];
            if (isNumber(token)) {
                stk.push(atoi(token.c_str()));
            } else {
                int num2 = stk.top();
                stk.pop();
                int num1 = stk.top();
                stk.pop();
                switch (token[0]) {
                    case '+':
                        stk.push(num1 + num2);
                        break;
                    case '-':
                        stk.push(num1 - num2);
                        break;
                    case '*':
                        stk.push(num1 * num2);
                        break;
                    case '/':
                        stk.push(num1 / num2);
                        break;
                }
            }
        }
        return stk.top();
    }
    bool isNumber(string& token) {
        return !(token == "+" || token == "-" || token == "*" || token == "/");
    }
};

代码思路

  1. int evalRPN(vector<string>& tokens)

    • stack<int> stk;:创建一个整数栈,用于存储操作数和中间结果。
    • int n = tokens.size();:获取输入的逆波兰表达式字符串数组的长度。
    • for (int i = 0; i < n; i++):遍历输入的字符串数组。
      • string& token = tokens[i];:获取当前遍历到的字符串。
      • if (isNumber(token)):调用 isNumber 函数判断当前字符串是否为数字。如果是数字,则将其转换为整数并推入栈中。使用 atoi(token.c_str()) 将字符串转换为整数。
      • 如果当前字符串不是数字,说明是运算符。从栈中弹出两个操作数 num2 和 num1,注意先弹出的是第二个操作数。然后根据运算符进行相应的运算,并将结果推入栈中。
    • return stk.top();:遍历结束后,栈中只剩下最终的结果,返回栈顶元素。
  2. bool isNumber(string& token):这个函数用于判断输入的字符串是否为数字。通过检查字符串是否不等于 "+""-""*""/" 这四个运算符来确定它是否为数字。如果不是运算符,就认为是数字。

  3. 逆波兰表达式的求值原理是:从左到右遍历表达式,如果遇到数字就将其推入栈中;如果遇到运算符,就从栈中弹出两个操作数,进行相应的运算,并将结果推入栈中。重复这个过程,直到遍历完整个表达式。最后,栈中剩下的唯一元素就是表达式的结果。

  4. 在这个代码中,使用栈来实现这个求值过程。当遇到数字时,将其转换为整数并推入栈中。当遇到运算符时,从栈中弹出两个操作数,进行相应的运算,并将结果推入栈中。通过这种方式,逐步计算出逆波兰表达式的结果。

224. 基本计算器

题目描述

224. 基本计算器

给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。

注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval() 。

运行代码

class Solution {
public:
    int calculate(string s) {
        stack<int> ops;
        ops.push(1);
        int sign = 1;

        int ret = 0;
        int n = s.length();
        int i = 0;
        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();
                i++;
            } else {
                long num = 0;
                while (i < n && s[i] >= '0' && s[i] <= '9') {
                    num = num * 10 + s[i] - '0';
                    i++;
                }
                ret += sign * num;
            }
        }
        return ret;
    }
};

代码思路

  1. int calculate(string s)
    • stack<int> ops;:创建一个整数栈,用于存储符号。
    • ops.push(1);:初始化栈,将初始符号设为正号(1)。
    • int sign = 1;:用于表示当前数字的符号。
    • int ret = 0;:存储最终的计算结果。
    • int n = s.length();:获取输入字符串的长度。
    • int i = 0;:用于遍历输入字符串的索引。
    • while (i < n):开始遍历输入字符串。
      • 如果当前字符是空格(' '),直接跳过,继续下一个字符,即 i++
      • 如果当前字符是加号('+'),设置当前数字的符号为栈顶符号,即 sign = ops.top();,然后继续下一个字符,即 i++
      • 如果当前字符是减号('-'),设置当前数字的符号为栈顶符号的相反数,即 sign = -ops.top();,然后继续下一个字符,即 i++
      • 如果当前字符是左括号('('),将当前符号推入栈中,即 ops.push(sign);,然后继续下一个字符,即 i++
      • 如果当前字符是右括号(')'),弹出栈顶符号,即 ops.pop();,然后继续下一个字符,即 i++
      • 如果当前字符是数字:
        • long num = 0;:用于存储当前数字。
        • while (i < n && s[i] >= '0' && s[i] <= '9'):当字符是数字时,将其转换为整数累加到 num 中,并继续下一个字符,即 i++
        • 将当前数字乘以符号累加到结果中,即 ret += sign * num;
  2. 这个算法使用栈来处理括号和符号。当遇到左括号时,将当前符号推入栈中,以便在遇到右括号时恢复之前的符号状态。
  3. 通过设置 sign 变量来确定当前数字的符号。当遇到加号或减号时,根据栈顶符号更新 sign
  4. 遍历输入字符串,将数字转换为整数并根据符号累加到结果中。当遇到括号时,使用栈来处理嵌套的表达式。

232. 用栈实现队列

题目描述

232. 用栈实现队列

请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(pushpoppeekempty):

实现 MyQueue 类:

  • void push(int x) 将元素 x 推到队列的末尾
  • int pop() 从队列的开头移除并返回元素
  • int peek() 返回队列开头的元素
  • boolean empty() 如果队列为空,返回 true ;否则,返回 false

说明:

  • 你 只能 使用标准的栈操作 —— 也就是只有 push to toppeek/pop from topsize, 和 is empty 操作是合法的。
  • 你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。

运行代码

class MyQueue {
private:
    stack<int> A, B;
public:
    MyQueue() {}
    void push(int x) {
        A.push(x);
    }
    int pop() {
        int peek = this->peek();
        B.pop();
        return peek;
    }
    int peek() {
        if (!B.empty())
          return B.top();
        if (A.empty()) 
          return -1;
        while (!A.empty()){
            B.push(A.top()), A.pop();
        }
        int res = B.top();
        return res;
    }

    bool empty() {
        return A.empty() && B.empty();
    }
};


/**
 * 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();
 */

代码思路

  • stack<int> A, B;:使用两个整数栈 A 和 B 来模拟队列。
  1. MyQueue():构造函数,用于初始化队列对象,不执行任何操作。

  2. void push(int x):将元素 x 推入栈 A。这个操作的时间复杂度为 。

  3. int pop():首先调用 peek() 方法获取队首元素。然后从栈 B 中弹出队首元素并返回。这个操作的时间复杂度为 (如果需要从栈 A 转移元素到栈 B,则为 ,其中 n 是当前栈 A 中的元素个数)。

  4. int peek()

    • 如果栈 B 不为空,直接返回栈 B 的栈顶元素,即队首元素。这个操作的时间复杂度为 。
    • 如果栈 A 为空,返回 -1,表示队列为空。
    • 如果栈 B 为空且栈 A 不为空,将栈 A 中的元素逐个弹出并推入栈 B,然后返回栈 B 的栈顶元素。这个操作的时间复杂度为 ,其中 n 是当前栈 A 中的元素个数。
  5. bool empty():判断栈 A 和栈 B 是否都为空,如果都为空则返回 true,表示队列为空;否则返回 false。这个操作的时间复杂度为 。

  6. 入队操作:将元素直接推入栈 A,相当于在队列的尾部添加元素。

  7. 出队和查看队首元素操作:如果栈 B 不为空,直接从栈 B 中弹出或查看元素,因为栈 B 的顺序与队列的顺序一致。如果栈 B 为空,将栈 A 中的元素逐个弹出并推入栈 B,这样栈 B 的顺序就与队列的顺序一致了,然后从栈 B 中进行出队或查看队首元素的操作。


http://www.kler.cn/a/326003.html

相关文章:

  • linux之调度管理(5)-实时调度器
  • Spring Events在大型项目中的最佳实践
  • 【配置后的基本使用】CMake基础知识
  • WebRTC视频 02 - 视频采集类 VideoCaptureModule
  • Sql进阶:字段中包含CSV,如何通过Sql解析CSV成多行多列?
  • 7.揭秘C语言输入输出内幕:printf与scanf的深度剖析
  • CSS 的user-select属性,控制用户是否能够选中文本内容
  • Java知识要点及面试题
  • 确保从IP池提取的IP是可用的对于数据抓取或其他网络活动至关重要。以下是一些确保IP可用性的有效方法:
  • 创新车展模式 焕新直播生态——第十一届麓谷汽车文化节圆满收官
  • 2024前端技术发展概况
  • Linux RCE 利用打印机服务 CVE-2024-47177
  • 【Redis】初识 Redis
  • 城市空间设计对居民生活质量的影响:构建宜居城市的蓝图
  • 基于SpringBoot实现QQ邮箱发送短信功能 | 免费短信服务
  • Nacos 安全使用最佳实践 - 访问控制实践
  • Redis 基础数据改造
  • AI绘画另类人像写真教程:用SD的 Reactor 实现换脸,效果真的很逼真!请谨慎使用
  • 基于大数据的商品推荐及可视化系统
  • E34.【C语言】位段练习题
  • 使用Python实现图形学的阴影体积算法
  • 秘密武器与选择指南
  • maven给springboot项目打成jar包 maven springboot打包配置
  • 深入解析 NoSQL 数据库的分类与特点
  • Qt5和Qt6获取屏幕的宽高,有区别
  • CSS宽度和高度