-
题目描述
请写一个整数计算器,支持加减乘三种运算和括号。 -
输入输出
-
思路
- 和 数据结构 课本上的实现计算器还不太相同,课本上采用的是开辟两个栈,一个存放括号、运算符,一个存放数值根据栈内运算符的优先级(()的优先级最低),下一个是优先级高的运算符,就压栈,优先级低的运算符,就弹栈一个运算符+两个数值,计算结果再压栈
- 这个是只用到一个栈,存放各部分的结果值(带符号的存放),(
一对括号里的表达式值
和两个运算符之间的 数值
分别是一个部分),然后最后一次弹栈相加,为所要的结果 - 需要注意的是,所给表达式中 具有括号的子表达式,需要递归求得结果(可以把一对括号的内容理解为一个number,只不过需要我们递归求出),递归结束返回值number,接着执行下面的压栈
- 需要注意的是,开始默认的运算符为 ‘+’,默认的数值为 0,当表达式以负数开头的时候,实际上第一次是压栈了一个 + 0 ,接着下次就是记录 负号 ,和数值
-
代码分析
- 外层循环控制遍历每个字符
- 开始分支先判断是否为(),是就需要递归求出括号里面的值,反悔number值,接着执行后面的压栈
- 接着分支判断字符是否为数字(
Character.isDigit()
),是数字,就进入下次循环判 直到求出完整的数字 - 最后分支判断是否为运算符 或者 最后一个字符,(刚进入分支还是记录的上一位的number和 number的前面的运算符,还没压栈,
+、-
压栈,若是*、\
就弹出上 上 一个栈内元素 与 正准备压栈的元素 进行运算后压栈),然后才是记录本次判断的运算符,接着下一轮循环
-
补充
算法
- 用栈保存各部分计算的和
- 遍历表达式
- 遇到数字时继续遍历求这个完整的数字的值
- 遇到左括号时递归求这个括号里面的表达式的值
- 遇到运算符时或者到表达式末尾时,就去计算上一个运算符并把计算结果push进栈,然后保存新的运算符
- 如果是+,不要计算,push进去
- 如果是-,push进去负的当前数
- 如果是×、÷,pop出一个运算数和当前数作计算
- 最后把栈中的结果求和即可
- 解答
梦开始的地方没错了!
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
* 返回表达式的值
* @param s string字符串 待计算的表达式
* @return int整型
*/
public int solve (String s) {
// write code here
//初始化栈
Stack<Integer> stack = new Stack<>();
//结果
int sum = 0;
//默认数字,运算符
int number = 0;
//默认的第一个数字前的运算符为 +
char sign = '+';
//字符串转化字符数组
char[] arr = s.toCharArray();
int n = s.length();
//对字符数组每个元素遍历
for(int i = 0;i<n;i++){
char c = arr[i];
//是否为左括号
if(c == '('){
int j = i + 1;
//默认是1对括号
int counterPar = 1;
while(counterPar > 0){
//统计是否存在括号嵌套的情况
if(arr[j] == '('){
counterPar++;
}
if(arr[j] == ')'){
counterPar--;
}
//向后直到找到右括号
j++;
}
//遇到左括号递归求这个括号里面表达式的值
//就是求左括号 到 右括号 之间 表达式的 值,返回值为 number,下面接着进栈
number = solve(s.substring(i + 1,j - 1));
//下一次就要从 j 开始,因为后面还有一个 i ++;
i = j - 1;
}
//是否为数字,是数字就求完整的数字值,每次循环都进这个分支,直到出现运算符
if(Character.isDigit(c)){
number = number * 10 + c - '0';
}
//不是数字 或者 为最后一个字符
if( ! Character.isDigit(c) || i == n - 1){
if(sign == '+'){
//是 + 先把 数字 压栈,等会全部数字出栈之和即为所求
stack.push(number);
}
else if(sign == '-'){
//是 - 压栈该数字的相反数
stack.push( -1 * number);
}
else if(sign == '*'){
//是 * ,弹栈算出结果,在压栈
stack.push(stack.pop() * number);
}
else if(sign == '/'){
//是 / ,弹栈算出结果,在压栈
stack.push(stack.pop() / number);
}
//每次结束,数字恢复默认值
number = 0;
// 遇到运算符时或者到表达式末尾时,就去计算上一个运算符并把计算结果push进栈,然后保存新的运算符
//运算符为 当前压栈数字 前面近邻的那个
sign = c;
//如果是负数 在 表达式的最前面 ,会先压栈 +0,然后在记录当前 负号,开始接下来的数字
}
}
while(!stack.isEmpty()){
sum += stack.pop();
}
return sum;
}
}