LeetCode题练习与总结:基本计算器 Ⅱ--227

ops/2024/9/20 1:26:12/ 标签: 算法, 数据结构, LeetCode, Java, , 数学, 字符串

一、题目描述

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

整数除法仅保留整数部分。

你可以假设给定的表达式总是有效的。所有中间结果将在 [-2^31, 2^31 - 1] 的范围内。

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

示例 1:

输入:s = "3+2*2"
输出:7

示例 2:

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

示例 3:

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

提示:

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

二、解题思路

这个问题可以使用(stack)来解决。我们使用两个,一个用于存储操作数,另一个用于存储操作符。遍历字符串s,根据遇到的字符类型(数字、操作符或空格)进行相应的处理。

  1. 当遇到数字时,将其转换为整数并存储在操作数中。
  2. 当遇到操作符时,需要考虑操作符的优先级。如果当前操作符的优先级高于顶操作符的优先级,则直接将当前操作符入。否则,需要先计算顶的操作符,并将结果重新入,然后比较当前操作符与新的顶操作符的优先级。
  3. 当遇到空格时,忽略它。
  4. 对于乘法和除法,因为它们的优先级高于加法和减法,所以一旦遇到乘号或除号,需要立即计算结果,并将结果入
  5. 对于加法和减法,可以直接将操作数入,因为它们可以在最后一起计算。

以下是具体的步骤:

  • 初始化两个:一个用于存储操作数(nums),另一个用于存储操作符(ops)。
  • 遍历字符串s,对于每个字符c
    • 如果c是空格,则忽略。
    • 如果c是数字,则解析出完整的数字并压入nums
    • 如果c是操作符(+-*/):
      • 如果ops为空或者顶的操作符是(,则直接将c压入ops
      • 如果c*/,则从nums中弹出两个操作数进行计算,并将结果压回nums
      • 如果c+-,并且ops顶不是(,则从nums中弹出两个操作数进行计算,并将结果压回nums,然后将c压入ops
  • 遍历完成后,如果ops中还有操作符,则继续从nums中弹出操作数进行计算,直到ops为空。
  • 最后,nums中的唯一元素即为表达式的结果。

三、具体代码

import java.util.Stack;public class Solution {public int calculate(String s) {Stack<Integer> nums = new Stack<>();Stack<Character> ops = new Stack<>();for (int i = 0; i < s.length(); i++) {char c = s.charAt(i);if (c == ' ') continue;if (Character.isDigit(c)) {int num = 0;while (i < s.length() && Character.isDigit(s.charAt(i))) {num = num * 10 + (s.charAt(i) - '0');i++;}i--; // since the for loop also increments inums.push(num);} else if (c == '(') {ops.push(c);} else if (c == ')') {while (ops.peek() != '(') {nums.push(applyOp(ops.pop(), nums.pop(), nums.pop()));}ops.pop();} else if (c == '+' || c == '-' || c == '*' || c == '/') {while (!ops.isEmpty() && hasPrecedence(c, ops.peek())) {nums.push(applyOp(ops.pop(), nums.pop(), nums.pop()));}ops.push(c);}}while (!ops.isEmpty()) {nums.push(applyOp(ops.pop(), nums.pop(), nums.pop()));}return nums.pop();}public boolean hasPrecedence(char op1, char op2) {if (op2 == '(' || op2 == ')') return false;if ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-')) return false;return true;}public int applyOp(char op, int b, int a) {switch (op) {case '+': return a + b;case '-': return a - b;case '*': return a * b;case '/': return a / b;}return 0;}
}

请注意,代码中的applyOp方法假设中的操作数顺序是正确的,并且对于减法和除法,ab的顺序很重要(a是被操作数,b是操作数)。代码也处理了括号的情况,确保在遇到右括号时,所有括号内的表达式都会被计算。

四、时间复杂度和空间复杂度

1. 时间复杂度
  • 遍历字符串s:假设字符串s的长度为n,则遍历字符串的时间复杂度为O(n)
  • 解析数字:在遍历过程中,每次遇到数字,需要解析出完整的数字。在最坏的情况下,数字可能连续出现,这意味着对于每个数字字符,我们需要进行一次操作。因此,解析数字的总操作次数也是O(n)
  • 应用操作符:在遍历字符串的过程中,每次遇到操作符,我们可能需要从中弹出元素进行计算,然后将结果压回中。在最坏的情况下,可能需要对每个操作符都进行这样的操作。由于每个操作符最多被处理一次,因此这一步的时间复杂度也是O(n)

综上所述,总的时间复杂度为O(n),其中n字符串s的长度。

2. 空间复杂度
  • 操作数nums:在最坏的情况下,所有数字都直接入,没有进行任何计算,因此的大小可能达到O(n)
  • 操作符ops:在最坏的情况下,所有操作符都直接入,没有进行任何计算,因此的大小可能达到O(n)

综上所述,总的空间复杂度为O(n),其中n字符串s的长度。

这里的O(n)表示算法的复杂度与输入字符串的长度成线性关系。在实际情况中,由于数字不会连续占据整个字符串,操作符和操作数的大小通常会小于n,但最坏情况下的复杂度分析仍然是O(n)

五、总结知识点

  • (Stack)的使用

  • 字符和字符串操作

    • 使用char类型来处理单个字符。
    • 使用String类的charAt方法来获取字符串中指定位置的字符。
    • 使用Character.isDigit方法来判断一个字符是否是数字。
  • 数字解析

    • 通过循环和字符减去’0’的方式,将字符串中的连续数字字符转换为整数。
  • 运算符优先级

    • 在处理算术表达式时,需要根据运算符的优先级来决定计算的顺序。
    • 使用hasPrecedence方法来判断当前运算符与顶运算符的优先级关系。
  • 条件逻辑

    • 使用if-else语句来处理不同类型的字符(空格、数字、运算符、括号)。
    • 使用while循环来处理连续的数字字符,以及应用运算符。
  • 异常处理

    • 虽然在给出的代码中没有显示异常处理,但在实际应用中,应当考虑除法操作可能导致的ArithmeticException(如除以零)。
  • 递归下降

    • 在处理括号时,实际上隐式地使用了递归下降解析的原理,通过递归地将括号内的表达式视为一个子表达式来处理。
  • 运算符应用

    • 使用applyOp方法来根据运算符执行相应的算术运算。
  • 算法逻辑

    • 理解和实现一个基本的算术表达式求值算法,这涉及到算法设计的基本概念。
  • 类型转换

    • 在将字符转换为整数时,涉及到从charint的类型转换。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。


http://www.ppmy.cn/ops/111010.html

相关文章

DesignPattern设计模式

1 前言 1.1 内容概要 理解使用设计模式的目的掌握软件设计的SOLID原则理解单例的思想&#xff0c;并且能够设计一个单例理解工厂设计模式的思想&#xff0c;能够设计简单工厂&#xff0c;理解工厂方法了解建造者模式的思想&#xff0c;掌握其代码风格理解代理设计模式的思想&a…

代码随想录训练营 Day60打卡 图论part10 SPFA算法 Bellman-Ford 之判断负权回路 Bellman-Ford 之单源有限最短路

代码随想录训练营 Day60打卡 图论part10 一、Bellman_ford 队列优化算法&#xff08;又名SPFA&#xff09; 例题&#xff1a;卡码94. 城市间货物运输 I 题目描述 某国为促进城市间经济交流&#xff0c;决定对货物运输提供补贴。共有 n 个编号为 1 到 n 的城市&#xff0c;通过…

[数据集][目标检测]葡萄成熟度检测数据集VOC+YOLO格式1123张3类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1123 标注数量(xml文件个数)&#xff1a;1123 标注数量(txt文件个数)&#xff1a;1123 标注…

Python、PyTorch与cuda的版本对应表

常见的Python和PyTorch版本对应关系。 PyTorch版本对应的PythonPyTorch1.0Python 2.7&#xff0c;3.5&#xff0c;3.6&#xff0c;3.7PyTorch1.1Python 2.7&#xff0c;3.5&#xff0c;3.6&#xff0c;3.7PyTorch1.2Python 2.7&#xff0c;3.5&#xff0c;3.6&#xff0c;3.7P…

深度优先算法,广度优先算法,hill climbing,贪心搜索,A*算法,启发式搜索算法是什么,比起一般搜索法算法有什么区别

深度优先算法&#xff08;Depth-First Search, DFS&#xff09; 深度优先搜索是一种用于遍历或搜索树或图的算法。它沿着树的深度遍历树的节点&#xff0c;尽可能深地搜索树的分支。当节点v的所在边都已被探寻过&#xff0c;搜索将回溯到发现节点v的那条边的起始节点。这一过程…

PyCharm使用ipynb文件交互式绘图

PyCharm配置 Jupyter Notebook 这个文章很全 PyCharm配置 Jupyter Notebook plotly方法 终端安装&#xff1a; pip install plotlyimport plotly.graph_objects as go import numpy as np# 示例数据 X np.linspace(-5, 5, 100) Y np.linspace(-5, 5, 100) X, Y np.meshg…

cmake的出现是为了解决什么问题 cmake是干嘛的

CMake 是一个跨平台的构建系统生成器&#xff0c;它的出现主要是为了应对和解决以下几个问题&#xff1a; 1. 构建系统的复杂性 在软件开发中&#xff0c;特别是大型项目&#xff0c;构建系统往往变得复杂。CMake 旨在简化构建过程&#xff0c;通过提供一个统一的配置和构建机…

【论文笔记】AutoLFADS (Nature Methods, 2022)

相关链接&#xff1a; Is This Tutorial For You? - AutoLFADS TutorialDANDI ArchiveNonhuman Primate Reaching with Multichannel Sensorimotor Cortex Electrophysiology Abstract 通过深度神经群体动力学模型实现最先进的性能需要对每个数据集进行广泛的超参数调整。 Au…

rocketmq-client5.2手动给生产者和消费者设置access-key和secret-key值

生产者 import org.apache.rocketmq.acl.common.AclClientRPCHook; import org.apache.rocketmq.acl.common.SessionCredentials; import org.apache.rocketmq.client.producer.DefaultMQProducer; import org.apache.rocketmq.client.producer.SendResult; import org.apache…

el-table 如何实现行列转置?

在某些需求里需要用到 行列转置 的表格&#xff0c;但 el-table 提供的基本表格是不支持行列转置的&#xff0c;这样就需要对这个表格进行二次开发。下面来看具体实现的效果&#xff1a; 具体实现方式 基本原理就是对原有的可渲染的数据结构进行处理&#xff0c;表头与表格数…

QT使用事件事件和绘制事件实现简易时钟

这个时钟实现的底层原理主要是利用 Qt 的绘图机制和定时器。首先&#xff0c;设置固定大小的窗口&#xff0c;创建定时器并连接到槽函数&#xff0c;定时器每秒钟触发一次&#xff0c;触发窗口重绘。在paintEvent函数中&#xff0c;使用QPainter进行绘图&#xff0c;绘制圆形表…

React 中,Hook 是一个特定的概念

在 React 中&#xff0c;Hook 是一个特定的概念&#xff0c;主要是为了提供函数组件中对状态和生命周期功能的支持。它们之所以被称为 “Hooks”&#xff08;钩子&#xff09;&#xff0c;是因为它们提供了一种“钩住”组件功能的方式&#xff0c;让你能够在函数组件中“挂钩”…

Redis实现发布/订阅功能(实战篇)

前言 博主在学习 Redis 实现发布订阅功能的时候&#xff0c;踩了太多的坑。 不是讲解不详细&#xff0c;看的一知半解&#xff1b;就是代码有问题&#xff0c;实际压根跑不起来&#xff01; 于是博主萌生了自己写一个最新版且全程无错的博客供各位参考。希望各位不要把我才过…

ngrok | 内网穿透,支持 HTTPS、国内访问、静态域名

前言 当我们需要把本地开发的应用展示给外部用户时&#xff0c;常常会因为无法直接访问而陷入困境。 就为了展示一下&#xff0c;买服务、域名&#xff0c;搭环境&#xff0c;费钱又费事。 那有没有办法&#xff0c;让客户直接访问自己本机开发的应用呢&#xff1f; 这种需…

SAP自动化-ME12批量更新最后一行的价格

Python源码 #-Begin-----------------------------------------------------------------#-Includes-------------------------------------------------------------- import sys, win32com.client import os import time#-Sub Main-----------------------------------------…

H5依赖安装

依赖安装 git和sourceTree编辑器使用vscode下载nvm 和nodejs git和sourceTree 使用 ssh-keygen -t rsa 进行密钥获取 git下载地址&#xff1a;https://git-scm.com/ sourceTree下载地址&#xff1a;https://www.sourcetreeapp.com/ 编辑器使用vscode 最新版网址&#xff1a;…

Redis_RDB持久化

基于RDB的持久化方式会把当前内存中所有的redis键值对数据以快照的方式写入硬盘文件中&#xff0c;如果需要恢复数据&#xff0c;就把快照文件读到内存中。 RDB快照文件是经压缩的二进制格式的文件&#xff0c;它的储存路径不仅可以在redis服务器启动前通过配置参数来设置&…

字节内推-前端-校招-实习

字节-生活服务-营销前端&#xff0c;校招、实习均有名额&#xff0c;快来一起战斗吧&#xff5e; &#x1f525;&#x1f525;&#x1f525; 业务发展快&#xff0c;团队氛围好&#xff0c;成长空间大。 &#x1f680; 业务&#xff1a;可以理解成对标美团&#xff0c;负责生活…

CSP-J 计算机软件系统

文章目录 前言系统软件1. 操作系统&#xff08;Operating System, OS&#xff09;2. 语言处理程序&#xff08;Language Processors&#xff09;3. 数据库管理系统&#xff08;Database Management System, DBMS&#xff09;4. 辅助程序&#xff08;Utility Programs&#xff0…

CORS漏洞及其防御措施:保护Web应用免受攻击

1. 背景- 什么是CORS&#xff1f; 在当今互联网时代&#xff0c;Web 应用程序的架构日益复杂。一个后端服务可能对应一个前端&#xff0c;也可能与多个前端进行交互。跨站资源共享&#xff08;CORS&#xff09;机制在这种复杂的架构中起着关键作用&#xff0c;但如果配置不当&…