题目:

给你一个字符串表达式 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. 网络io与select

    我们知道网络IO模型一共有5种,这里我们主要讨论同步IO和select多路复用的情况. 我们先从一个简单的TCP服务器的代码出发,来讨论一下这个是怎么实现的. 一个十分简单的TCP服务器 一个简单的T ...

  2. day07-JavaScript04

    JavaScript04 11.DOM02 11.3HTML-DOM文档说明 11.3.1基本介绍 在HTML DOM(文档对象模型)中,每个部分都是节点: 1)文档本身是文档节点 2)所有HTML元 ...

  3. Android源码在线查看网站

    一.aospxref http://aospxref.com/ 优点:更新速度快 缺点:历史版本较少 二.androidxref http://androidxref.com/ 优点:历史版本较多 缺 ...

  4. Django:Nginx 启动,无法加载样式,无法加载静态文件

    一般是由于 Nginx 配置文件的问题 # 编辑 Nginx 配置文件 vim /etc/nginx/nginx.conf # 如果出现下面这个 use nginx 就需要改成 use root 保存 ...

  5. 【732. 我的日程安排表 III】差分数组

    class MyCalendarThree { private TreeMap<Integer, Integer> cnt; public MyCalendarThree() { cnt ...

  6. 【Spring注解驱动开发】面试官再问你BeanPostProcessor的执行流程,就把这篇文章甩给他!

    写在前面 在前面的文章中,我们讲述了BeanPostProcessor的postProcessBeforeInitialization()方法和postProcessAfterInitializati ...

  7. P9966 [THUPC 2024 初赛] 机器人 题解

    细节大模拟. 题意 一堆机器人在一起,每个人有左右手和一些指令,依次执行并输出结果. 做法 首先这种指令的执行还算是比较简单的大模拟,一个个实现即可,在此给出我的定义. struct Robot{ i ...

  8. #对偶图最短路,网络流#洛谷 4001 [ICPC-Beijing 2006]狼抓兔子

    题目 网格图最小割\((n,m\leq 1000)\) 分析 首先网络流可以过,但是由于无向图,所以残量网络容量也为\(w\),\(Dinic\)玄学AC,代码就不贴了 那有没有其它方法呢,网格图显然 ...

  9. #数位dp,高精度#洛谷 2235 [HNOI2002]Kathy函数

    题目 分析 首先这个\(f\)函数其实求的是二进制下的回文数,简单证明一下 设\(n\)在二进制下的回文数为\(n'\),第一二条显然 第三条\(f(2n)=f(n)\Rightarrow \over ...

  10. JDK10的新特性:本地变量类型var

    目录 简介 为什么我们需要var var使用在什么地方 var不能用在什么地方 其他var的特点 总结 简介 java以面向对象的特性显著于世并得到了蓬勃的发展.在语言的发展过程中,为了让java语言 ...