【数据结构与算法】双栈法解决表达式计算问题

news/2024/11/7 12:36:19/

文章目录

  • 一、基本计算器Ⅰ
  • 二、基本计算器Ⅱ

一、基本计算器Ⅰ

题目链接

题目描述:

给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval() 。

示例 1:

输入:s = “1 + 1”
输出:2

示例 2:

输入:s = " 2-1 + 2 "
输出:3

示例 3:

输入:s = “(1+(4+5+2)-3)+(6+8)”
输出:23

提示:

1 <= s.length <= 3 * 105
s 由数字、‘+’、‘-’、‘(’、‘)’、和 ’ ’ 组成
s 表示一个有效的表达式
‘+’ 不能用作一元运算(例如, “+1” 和 “+(2 + 3)” 无效)
‘-’ 可以用作一元运算(即 “-1” 和 “-(2 + 3)” 是有效的)
输入中不存在两个连续的操作符
每个数字和运行的计算将适合于一个有符号的 32位 整数

思路分析
用两个栈:
nums:存数字字符
ops:存符号字符

从前向后遍历字符串,因为这道题只有+/-,所以不用考虑符号优先级问题。
遍历过程有以下几种情况:

1️⃣ 空格:直接跳过
2️⃣ 数字字符:向后遍历取出完整数字,放入nums中。
3️⃣ (:直接放入ops中,等待)与之匹配
4️⃣ ):利用两个栈计算,直到遇到(,结果放入nums中,再把(出栈
5️⃣ +/-先把前面能计算的都计算了(一直算到遇到(为止),结果放入nums中,符号放入ops中

关于首字符带符号的处理:
可以先往nums中加一个0元素,这样-就可以算进去。

关于(+(-的处理:
每次遇到+/-的时候判断前一个字符是否是(,如果是就往nums中添加0。

关于空格的处理:
这里不能遇到空格后跳过,因为可能出现"1-( -2)"这种情况,所以先预处理字符串把空格全部消掉。

代码如下:

class Solution {
public:stack<int> nums;stack<char> ops;unordered_map<char, function<int(int, int)>> hash = {{'+', [](int x, int y){return x + y;}},{'-', [](int x, int y){return x - y;}},};void delBlack(string& s){auto it = s.find(" ");while(it != -1){s.replace(it, 1, "");it = s.find(" ");}}void calc(){if(nums.size() < 2 || ops.empty()) return;int right = nums.top();nums.pop();int left = nums.top();nums.pop();char op = ops.top();ops.pop();nums.push(hash[op](left, right));}int calculate(string s) {// 去掉空格delBlack(s);// 防止首元素为-nums.push(0);int n = s.size();for(int i = 0; i < n; i++){if(isdigit(s[i]))// 数字字符{int cur = 0, j = i;while(j < n && isdigit(s[j])){cur = cur * 10 + (s[j++] - '0');}nums.push(cur);i = j - 1;}else// 符号字符{if(s[i] == '(') ops.push(s[i]);else if(hash.count(s[i]))// + -{// "(+"情况if (i > 0 && (s[i - 1] == '(')) {nums.push(0);}// 入栈前先把前面的计算了while(ops.size() && ops.top() != '('){calc();}ops.push(s[i]);}else// ')'{// 一直算到 '('while(ops.size() && ops.top() != '('){calc();}ops.pop();}}}while(!ops.empty())calc();return nums.top();}
};

二、基本计算器Ⅱ

题目链接

题目描述:

给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
整数除法仅保留整数部分。
你可以假设给定的表达式总是有效的。所有中间结果将在 [-231, 231 - 1] 的范围内。
注意:不允许使用任何将字符串作为数学表达式计算的内置函数,比如 eval() 。

示例 1:

输入:s = “3+2*2”
输出:7

示例 2:

输入:s = " 3/2 "
输出:1

示例 3:

输入:s = " 3+5 / 2 "
输出:5

提示:

1 <= s.length <= 3 * 105
s 由整数和算符 (‘+’, ‘-’, ‘*’, ‘/’) 组成,中间由一些空格隔开
s 表示一个 有效表达式
表达式中的所有整数都是非负整数,且在范围 [0, 231 - 1] 内
题目数据保证答案是一个 32-bit 整数

思路分析:
这道题跟上面一道题多了一个符号优先级问题,为了解决这个问题,可以加入一个符号优先级表:

unordered_map<char,int> oper_pri = {{'+',1},{'-',1},{'*',2},{'/',2},
};

当遇到符号+ - * /的时候先判断优先级oper_pri[ops.top()] >= oper_pri[s[i]]的时候说明可以计算前面的表达式了,先计算前面的,然后再把符号添加进ops中。

那遇到)也要计算前面的,需不需要判断优先级呢?
不需要,因为再()内部已经自动处理完了。

代码如下:

class Solution {
public:stack<int> nums;stack<char> ops;unordered_map<char, function<int(int, int)>> hash = {{'+', [](int x, int y){return x + y;}},{'-', [](int x, int y){return x - y;}},{'*', [](int x, int y){return x * y;}},{'/', [](int x, int y){return x / y;}},};unordered_map<char,int> oper_pri = {{'+',1},{'-',1},{'*',2},{'/',2},};void delBlack(string& s){auto it = s.find(" ");while(it != -1){s.replace(it, 1, "");it = s.find(" ");}}void calc(){if(nums.size() < 2 || ops.empty()) return;int right = nums.top();nums.pop();int left = nums.top();nums.pop();char op = ops.top();ops.pop();nums.push(hash[op](left, right));}int calculate(string s) {// 去掉空格delBlack(s);// 防止首元素为-nums.push(0);int n = s.size();for(int i = 0; i < n; i++){if(isdigit(s[i]))// 数字字符{int cur = 0, j = i;while(j < n && isdigit(s[j])){cur = cur * 10 + (s[j++] - '0');}nums.push(cur);i = j - 1;}else// 符号字符{if(s[i] == '(') ops.push(s[i]);else if(hash.count(s[i]))// + - * /{// "(+"情况if (i > 0 && (s[i - 1] == '(')) {nums.push(0);}// 入栈前先把前面的计算了while(ops.size() && ops.top() != '(' && oper_pri[ops.top()] >= oper_pri[s[i]]){calc();}ops.push(s[i]);}else// ')'{// 一直算到 '('while(ops.size() && ops.top() != '('){calc();}ops.pop();}}}while(!ops.empty())calc();return nums.top();}
};



http://www.ppmy.cn/news/553500.html

相关文章

在AI到来的时代,作为技术人,持续学习是我们的秘密武器哦!

✨求关注~ &#x1f600;博客&#xff1a;www.protaos.com 在AI到来的时代&#xff0c;作为技术人&#xff0c;持续学习是我们的秘密武器哦&#xff01;&#x1f60e;&#x1f4da; 首先&#xff0c;让我们和最酷的技术圈子保持紧密的联系。订阅那些超级棒的技术博客和新闻网站…

Redis该如何监控

原文地址 mp.weixin.qq.com 本文重点讲述 Redis 的哪些 metrics 需要重要监控&#xff08;篇幅有限&#xff0c;不能涵盖所有&#xff09;&#xff0c;以及我们如何获取这些 metrics 数据。从而确保对我们应用至关重要的 Redis 是否健康运行&#xff0c;以及当出现问题时能及时…

Excel单元格使用xlwings包调用python函数的公式,截取子网页(标题)的试验 问题求助CSDN

Excel单元格使用xlwings包调用python函数的公式&#xff0c;截取子网页&#xff08;标题&#xff09;的试验 问题求助CSDN Python 环境&#xff1a;python3.7 的conda上的py3环境 Excel 2010 Excel单元格布置 D114http://mp.weixin.qq.com/s?__bizMzU2MTgxNTE1Nw&mid2…

李宏毅机器学习2022春季-第八课和HW8

李宏毅2022课程视频全部以线上视频的形式给出&#xff08;已经全部录好&#xff0c;你可以选择短时间全部学完&#xff09;&#xff0c;上课时间会直播讲解额外的内容&#xff08;可以不听&#xff09;和作业&#xff08;建议一定要做&#xff09;&#xff0c;目前已更新到作业…

以小窥大:IO 卡顿探寻文件系统

从一个不寻常的 I/O 卡顿入手&#xff0c;发现苹果 APFS 的一个严重 bug。 近期有用户反馈频繁遇到了一个奇怪的严重卡顿问题&#xff0c;微信刷朋友圈和查看聊天都非常卡&#xff0c;主线程卡在最普通的 access, rename 等常见 I/O 系统调用&#xff0c;并且经常卡上百 ms&…

6.17 、Java初级:锁

1 同步锁 1.1 前言 经过前面多线程编程的学习,我们遇到了线程安全的相关问题,比如多线程售票情景下的超卖/重卖现象. 上节笔记点这里-进程与线程笔记 我们如何判断程序有没有可能出现线程安全问题,主要有以下三个条件: 在多线程程序中 有共享数据 多条语句操作共享数据 多…

IoC容器的设计(利用反射、注解和工厂模式实现)

1.实验要求 利用注解、反射和工厂模式设计一个简单的IoC容器该IoC容器包含3个注解和一个IoC容器类&#xff08;AnnotationConfigApplicationContext&#xff09;&#xff0c;其定义如下&#xff1a; 注解&#xff1a; 注解含义Component标注BeanAutowired标注需要被注入的对…

rust abc(1): 最小环境搭建

文章目录 1. 目的2. 命令集合3. 安装或更新 rust3.1 命令3.2 运行结果 4. 包管理工具 Cargo5. 创建 Rust 的 Hello World 程序: 单个文件6. 创建 Rust 的 Hello World 工程&#xff1a; 基于 Cargo6.1 cargo new 创建工程6.2 cargo run6.3 完整输出6.4 解释 7. IDE/编辑器8. Re…