问题描述
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
整数除法仅保留整数部分。
示例 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 整数
解题思路:借助栈实现
由于乘除优先于加减计算,因此不妨考虑先进行所有乘除运算,并将这些乘除运算后的整数值放回原表达式的相应位置,而对于加法和减法,加法直接入栈,减法取相反数入栈,则随后整个表达式的值,就等于一系列整数(包含负数)相加后的值。
基于此,我们可以用一个栈,保存这些(进行乘除运算后的)整数的值。对于加减号后的数字,将其直接压入栈中;对于乘除号后的数字,可以直接与栈顶元素计算,并替换栈顶元素为计算后的结果。
具体来说,遍历字符串 s,并用变量 preSign记录每个数字之前的运算符,对于第一个数字,其之前的运算符视为加号。每次遍历到数字末尾时,根据 preSign 来决定计算方式:
- 加号:将数字压入栈;
- 减号:将数字的相反数压入栈;
- 乘除号:计算数字与栈顶元素,并将栈顶元素替换为计算结果。
代码实现中,若读到一个运算符,或者遍历到字符串末尾,即认为是遍历到了数字末尾。处理完该数字后,更新 preSign 为当前遍历的字符。
遍历完字符串 s 后,将栈中元素累加,即为该字符串表达式的值。
代码实现
class Solution {
public int calculate(String s) {
int n=s.length();
//初始的前序运算符为加号,因为第一个出现的是数字
char preSign='+';
//使用栈来保存当前计算的结果
Stack<Integer> stack=new Stack<Integer>();
//num用来表示当前待入栈的数值大小
int num=0;
for(int i=0;i<n;i++){
char ch=s.charAt(i);
//如果该位置字符是数字,那么我们考虑将之前的数字和该位置上的数字组合成一个整数
if(Character.isDigit(ch)){
num=num*10+ch-'0';
}
//如果该位置不是数字,并且该位置也不是空字符串或者是最后一个字符,那么它一定是个运算符
if(!Character.isDigit(ch) && ch!=' ' || i==(n-1)){
//对于加减号,直接入栈,注意,我们使用的都是前一个运算符。因为该运算符的右边的数值还没有
if(preSign=='+'){
stack.push(num);
}else if(preSign=='-'){
stack.push(-num);
}else if(preSign=='*'){
stack.push(stack.pop()*num);
}else{
stack.push(stack.pop()/num);
}
//遇到了运算符,那么遍历数字就要重新开始
num=0;
//前序运算符更新
preSign=ch;
}
}
int res=0;
//将栈中的数值都进行累加
while(!stack.empty()){
res=res+stack.pop();
}
return res;
}
}