题目:

给你一个字符串表达式 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 整数

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/basic-calculator-ii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

这道题和224.基本计算器思路一致,利用栈的特点来解决

建立双栈:

  • 使用栈nums:来存放操作数;
  • 使用栈ops:来存放操作符。

与224题不同的是多了几个操作符,且上一题中操作符的优先级一样,这一题有优先级的差别,就利用哈希表来存储优先级,键为操作符,值为优先级,优先级按照数学运算中操作符的优先级来限定。

将字符串s中的所有空格去掉,并转换成字符数组,从前往后进行遍历,根据当前遇到的字符进行分情况讨论:

  • 遇到左括号 (:就将其加入ops中,等待与之匹配的右括号 );
  • 遇到右括号 ):当ops中不为空时,还没遇到与之匹配的左括号时,就将已有的nums和ops进行计算,将结果放入nums中,当遇到与之匹配的左括号时,就将左括号弹出;
  • 遇到数字时:就将当前连续的整数取出,放入nums中;
  • 有新的操作符入栈时,如果ops栈顶操作符优先级 >= 新的操作符的优先级 ,就计算栈内元素,直到操作符为空或者左括号就继续将操作符入栈,后续遍历完s,再进行计算剩下的。

注意点(有一点改变):

1.第一个数可能为负数(-6):这样第一个操作符可能被认为 '减号',计算时没有前面的数与之计算,可以再最开始就加入一个0,变成 0-6这样结果也正好为-6;

2.为了防止括号内出现的首个字符为运算符,当遇到左括号 ( 时,就添加一个0,使之变为 ( 0,其实与224题效果一样,但是我觉得这个更好利于我理解一点。

代码:

  1 class Solution {
2 public int calculate(String s) {
3 Deque<Integer> nums = new ArrayDeque<>();
4 Deque<Character> ops = new ArrayDeque<>();
5 Map<Character, Integer> map = new HashMap<>(){{
6 put('+', 1);
7 put('-', 1);
8 put('*', 2);
9 put('/', 2);
10 put('%', 2);
11 put('^', 3);
12 }};
13 s = s.replaceAll(" ", "");
14 char[] cs = s.toCharArray();
15 int n = cs.length;
16 for(int i = 0; i < n; i++){
17 char c = cs[i];
18 //当前遇到左括号,就加入操作符栈
19 if(c == '('){
20 ops.addLast(c);
21 }else if(c == ')'){
22 //遇到右括号,就计算括号内的数
23 while(!ops.isEmpty()){
24 if(ops.pollLast() != '('){
25 calc(nums, ops);
26 }else{
27 //计算完括号内的数就弹出左括号
28 ops.pollLast();
29 }
30 }
31 }else{
32 if(isNum(c)){
33 int num = 0;
34 int j = i;
35 //取出当前整数
36 while(j < n && isNum(cs[j])){
37 num = num * 10 + (cs[j++] - '0');
38 }
39 nums.addLast(num);
40 i = j -1;
41 }else{
42 //处理遇到左括号时,应该变成(0
43 if(i > 0 && cs[i - 1] == '('){
44 nums.addLast(0);
45 }
46 //如果当前c是操作符就看当前操作符的优先级是否小于等于栈内的优先级
47 //如果是,才计算栈内的
48 while(!ops.isEmpty() && ops.peekLast() != '('){
49 char preop = ops.peekLast();
50 if(map.get(preop) >= map.get(c)){
51 calc(nums, ops);
52 }else{
53 break;
54 }
55 }
56 ops.addLast(c);
57 }
58 }
59 }
60 //遍历完后算剩下的所有
61 while(!ops.isEmpty()){
62 calc(nums, ops);
63 }
64 return nums.peekLast();
65 }
66 //计算方法
67 void calc(Deque<Integer> nums, Deque<Character> ops){
68 //如果操作数为空或者长度小于2
69 if(nums.isEmpty() || nums.size() < 2) return;
70 //如果操作符为空
71 if(ops.isEmpty()) return;
72 int b = nums.pollLast(), a = nums.pollLast();
73 char c = ops.pollLast();
74 int res = 0;
75 switch (c){
76 case '+':
77 res = a + b;
78 break;
79 case '-':
80 res = a - b;
81 break;
82 case '*':
83 res = a * b;
84 break;
85 case '/':
86 res = a / b;
87 break;
88 case '%':
89 res = a % b;
90 break;
91 case '^':
92 res = (int) Math.pow(a, b);
93 break;
94 }
95 nums.addLast(res);
96 }
97 //判断是否为数字
98 boolean isNum(char num){
99 return Character.isDigit(num);
100 }
101 }

 小知识:

1.在数学中优先级:与+、-、*、/相比,幂(^)的优先级最高,最先算。

2.java中运算符的优先级:

力扣227(java)-基本计算器Ⅱ(中等)的更多相关文章

  1. 力扣1689. 十-二进制数的最少数目-C语言实现-中等难度题

    题目 传送门 如果一个十进制数字不含任何前导零,且每一位上的数字不是 0 就是 1 ,那么该数字就是一个 十-二进制数 .例如,101 和 1100 都是 十-二进制数,而 112 和 3001 不是 ...

  2. 力扣1438. 绝对差不超过限制的最长连续子数组-C语言实现-中等难度

    题目 传送门 文本 给你一个整数数组 nums ,和一个表示限制的整数 limit,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等于 limit . 如果不存在满足条 ...

  3. 力扣1052. 爱生气的书店老板-C语言实现-中等难度

    题目 传送门 文本 今天,书店老板有一家店打算试营业 customers.length 分钟.每分钟都有一些顾客(customers[i])会进入书店,所有这些顾客都会在那一分钟结束后离开. 在某些时 ...

  4. 力扣算法经典第一题——两数之和(Java两种方式实现)

    一.题目 难度:简单 给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数, 并返回它们的数组下标. 你可以假设每种输入只会对应一 ...

  5. 【力扣leetcode】-787. K站中转内最便宜的航班

    题目描述: 有 n 个城市通过一些航班连接.给你一个数组 flights ,其中 flights[i] = [fromi, toi, pricei] ,表示该航班都从城市 fromi 开始,以价格 p ...

  6. 力扣算法题—069x的平方根

    实现 int sqrt(int x) 函数. 计算并返回 x 的平方根,其中 x 是非负整数. 由于返回类型是整数,结果只保留整数的部分,小数部分将被舍去. 示例 1: 输入: 4 输出: 2 示例 ...

  7. JS数据结构第六篇 --- 二叉树力扣练习题

    1.第226题:翻转二叉树 递归+迭代两种实现方式: /** 反转二叉树 * Definition for a binary tree node. * function TreeNode(val) { ...

  8. 力扣(LeetCode)删除排序链表中的重复元素II 个人题解

    给定一个排序链表,删除所有含有重复数字的节点,只保留原始链表中 没有重复出现 的数字. 思路和上一题类似(参考 力扣(LeetCode)删除排序链表中的重复元素 个人题解)) 只不过这里需要用到一个前 ...

  9. C++双指针滑动和利用Vector实现无重复字符的最长子串—力扣算法

    题目: 力扣原题链接:https://leetcode-cn.com/problems/longest-substring-without-repeating-characters/ 给定一个字符串, ...

  10. LeetCode 1244. 力扣排行榜

    地址 https://www.acwing.com/solution/LeetCode/content/5765/ 题目描述新一轮的「力扣杯」编程大赛即将启动,为了动态显示参赛者的得分数据,需要设计一 ...

随机推荐

  1. docker 资料整理

    docker 资料整理 基础概念 docker deamon 守护系统:简单理解就是docker的软件系统,管控这容器的开关. docker容器:从镜像启动到内存中形成动态运行,从编程角度,如果镜像是 ...

  2. py文件读写

    ''' 1.文件打开 open(文件名,模式) 2.文件关闭filename.close() 模式: 1.r 文件读,指针默认在文件开头 2.w 文件写,指针默认在开头 若有文件,则打开时写入覆盖原文 ...

  3. 25_H.264编码

    本文主要介绍一种非常流行的视频编码:H.264. 计算一下:10秒钟1080p(1920x1080).30fps的YUV420P原始视频,需要占用多大的存储空间? (10 * 30) * (1920 ...

  4. [TM4] TM4C123G Keil5 新建工程指南

    [TM4] TM4C123G Keil5 新建工程指南 keil新建工程,选择TM4C123GH6PM芯片,然后在CMSIS勾选CORE,DEVICE勾选Startup(如图),来到新工程界面 在So ...

  5. 首届实时渲染3D动画创作大赛结果公布,看大奖英伟达A6000花落谁家!

    根据评选标准,经过评委组层层选拔,首届实时渲染3D动画创作大赛,最终获奖结果出炉啦. 本次赛事报名人数达212人,入围作品共40份,其中Omniverse组11份,专业组15份,学生组14份.在宣布最 ...

  6. Lifecycle详细分析

    Lifecycle源码分析 目录介绍 01.Lifecycle的作用是什么 02.Lifecycle的简单使用 03.Lifecycle的使用场景 04.如何实现生命周期感知 05.注解方法如何被调用 ...

  7. js中订阅发布模式bus

    export default { list: {}, // 事件中心集中地 /** * 发布订阅 * @param {string} name 事件名 * @param [...args] */ $e ...

  8. Topshelf C# 开发 Windows 服务程序最简单的方式

    Topshelf 官方网站: http://topshelf-project.com/ Topshelf 文档地址: https://topshelf.readthedocs.io/en/latest ...

  9. linux安装crontab

    1.查看是否安装 rpm -qa | grep cron #没有输出内容说明没有安装 2.安装 yum -y install vixie-cron #cron 的主程序 yum -y install ...

  10. FFmpeg开发笔记(十)Linux环境给FFmpeg集成vorbis和amr

    ​FFmpeg内置了aac音频格式,在<FFmpeg开发实战:从零基础到短视频上线>一书的"5.2.2  Linux环境集成mp3lame"又介绍了如何给FFmpeg集 ...