问题描述
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
- 输入:s = “1 + 1”
- 输出:2
- 输入:s = " 2-1 + 2 "
- 输出:3
- 输入的字符串中只有 + , -, *, /这些除去数字之外的字符串, 且舒服的数字只有1-9。
思路分析
- 使用两个栈,一个是数字栈用来存在数字,一个是符号栈用来存放操作符(+,-,*,/)
- 从0开始遍历整个输入字符串,
- 如果当前index获取到的是数字,则push到数字栈中
- 如果当前index返回的是操作符。
- 如果操作符栈为空,则直接将操作符push到操作符栈中
- 如果当前操作符栈不为空,则对比当前操作符和栈顶操作符的计算优先级。
- 如果栈顶元素的优先级大于等于当前符号。则从数字栈中依次pop出两个元素v1, v2 ;然后从字符栈中pop出一个字符 ,计算出v2、v1 在该运算中的值val。将val压入数字栈顶,将当前的操作符压入操作符栈顶
- 如果栈顶元素的优先级小于当前的符号,则将当前符号压入符号栈
- 遍历完整个字符串后。 每次从符号栈中弹出一个运算符,从数字栈中弹出依次弹出两个值 v1, v2。 v2, v1 按照弹出的计算符运算之后得到v,将v压入数字栈
直到操作符栈为空,则数字栈栈顶的元素则为最终的值。
代码实现
package stack;
/**
* 基本计算器 (中缀表达式1)
* 给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
* 输入:s = "1 + 1"
* 输出:2
* 输入:s = " 2-1 + 2 "
* 输出:3
* <p>
* 输入的字符串中只有 + , -, *, /这些除去数字之外的字符串, 且舒服的数字只有1-9。
*/
public class BasicCalculator1 {
/**
* 数字栈,用来存在数字
*/
private java.util.Stack<Integer> numberStack = new java.util.Stack<>();
/**
* 符号栈,用来存放运算符号
*/
private java.util.Stack<Character> operatorStack = new java.util.Stack<>();
/**
* 实现逻辑,使用两个栈,一个是数字栈用来存在数字,一个是符号栈用来存放符号
* 从0开始遍历整个自负串,如果当前index获取到的是数字,则push到数字栈中
* 如果当前index返回的符号。
* 如果符号栈为空,则直接将符号push到符号栈中
* 如果当前符号栈不为空,则对比当前符号和栈顶符号的计算优先级。
* 如果栈顶元素的优先级大于等于当前符号。则从数字栈中依次pop出两个元素v1, v2 ;然后从字符栈中pop出一个字符 ,计算出v2、v1 在该运算中的值val。
* 将val压入数字栈顶,将当前的符号压入栈顶
* 如果栈顶元素的优先级小于当前的符号,则将当前符号压入符号栈
* 遍历完整个字符串后。 每次从符号栈中弹出一个运算符,从数字栈中弹出依次弹出两个值 v1, v2。 v2, v1 按照弹出的计算符运算之后得到v,将v压入数字栈
* 直到符号栈为空,则数字栈栈顶的元素则为最终的值。
*
* @param str
* @return
*/
public int calculate(String str) {
if (str == null || str.length() <= 0) {
return 0;
}
for (int i = 0; i < str.length(); i++) {
char curOperator = str.charAt(i);
if (isNumber(curOperator)) {
numberStack.push(Character.getNumericValue(curOperator));
continue;
}
/**
* 如果栈为空,则直接压入栈
*/
if (operatorStack.isEmpty()){
operatorStack.push(curOperator);
continue;
}
char topOperator = operatorStack.peek();
int topPriority = getPriority(topOperator);
int curPriority = getPriority(curOperator);
//如果符号栈栈顶的操作符的优先级高于当前操作符的优先级,则依次将数据栈中pop出两个数字,按照操作符栈顶的元素进行运算,并且将运算结果
//压入到数据栈中,然后将当前操作符压入到
if (topPriority >= curPriority){
Character operator = operatorStack.pop();
Integer num1 = numberStack.pop();
Integer num2 = numberStack.pop();
int res = calculate(num1, num2, operator);
numberStack.push(res);
operatorStack.push(curOperator);
continue;
}
//如果当前操作符的优先级高于操作栈顶的操作符的优先级,则将操作符压入操作数栈中
operatorStack.push(curOperator);
}
//遍历完成之后,每次从操作符栈中弹出一个操作符,从数据栈中依次弹出两个数字,进行运算,然后将运算结果压入数据栈中
while (!operatorStack.isEmpty()){
Character operator = operatorStack.pop();
Integer num1 = numberStack.pop();
Integer num2 = numberStack.pop();
int res = calculate(num1, num2, operator);
numberStack.push(res);
}
return numberStack.pop();
}
private int calculate(int num1, int num2, char operation){
switch (operation){
case '+':
return num1 + num2;
case '-':
return num2 - num1;
case '*':
return num1 * num2;
case '/':
return num2 / num1;
default:
System.out.println("错误的输入");
}
throw new RuntimeException("错误的输入");
}
/**
* 判断是否是数字
*
* @param cur
* @return
*/
private boolean isNumber(char cur) {
return Character.isDigit(cur);
}
/***
* 获取操作符的优先级, 数字越大优先级越高
* @param ch
* @return
*/
private int getPriority(char ch){
if (ch == '+' || ch == '-'){
return 1;
}
if (ch == '*' || ch == '/'){
return 2;
}
return -1;
}
public static void main(String[] args) {
System.out.println();
BasicCalculator1 calculator = new BasicCalculator1();
int res = calculator.calculate("2+3*5+4/4-6");
System.out.println(res);
}
}
题目升级
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
- 输入:s = “1 + 1”
- 输出:2
- 输入:s = " 2-1 + 2 "
- 输出:3
- 输入的字符串中只有 + , -, *, /这些除去数字之外的字符串, 输入的数字不在只限制1-9,可以是任意数字。
思路分析
- 实现逻辑,使用两个栈,一个是数字栈用来存在数字,一个是操作符栈用来存放操作符
- 从0开始遍历整个字符串串
- 如果当前index获取到的是数字,使用一个临时变脸temp将数字存储起来,temp的初始值为0, 每次遇到数字后 temp = temp * 10 + curNum;
- 如果当前index返回的操作符。
-
首先 将temp的数值压入数字栈中,然后再考虑操作符。
-
如果操作符栈为空,则直接将操作符push到操作符栈中
-
如果当前操作符栈不为空,则对比当前操作符和栈顶操作符的计算优先级。
-
如果栈顶元素的优先级大于等于当前操作符。则从数字栈中依次pop出两个元素v1, v2 ;然后从字符栈中pop出一个字符 ,计算出v2、v1 在该运算中的值val。将val压入数字栈顶,将当前的操作符压入栈顶
-
如果栈顶元素的优先级小于当前的操作符,则将当前操作符压入操作符栈
- 遍历完整个字符串后。将temp压入到数字栈中 每次从操作符栈中弹出一个运算符,从数字栈中弹出依次弹出两个值 v1, v2。 v2, v1 按照弹出的计算符运算之后得到v,将v压入数字栈
- 直到操作符栈为空,则数字栈栈顶的元素则为最终的值。
代码实现
package stack;
/**
* 基本计算器 (中缀表达式1)
* 给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
* 输入:s = "1 + 1"
* 输出:2
* 输入:s = " 2-1 + 2 "
* 输出:3
* <p>
* 输入的字符串中只有 + , -, *, /这些除去数字之外的字符串,输入的数字不再仅限制为1-9
*/
public class BasicCalculator2 {
/**
* 数字栈,用来存在数字
*/
private java.util.Stack<Integer> numberStack = new java.util.Stack<>();
/**
* 操作符栈,用来存放运算操作符
*/
private java.util.Stack<Character> operatorStack = new java.util.Stack<>();
/**
* 实现逻辑,使用两个栈,一个是数字栈用来存在数字,一个是操作符栈用来存放操作符
* 从0开始遍历整个字符串串
* 如果当前index获取到的是数字,使用一个临时变脸temp将数字存储起来,temp的初始值为0, 每次遇到数字后 temp = temp * 10 + curNum;
* 如果当前index返回的操作符。
* 首先 将temp的数值压入数字栈中,然后再考虑操作符。
* 如果操作符栈为空,则直接将操作符push到操作符栈中
* 如果当前操作符栈不为空,则对比当前操作符和栈顶操作符的计算优先级。
* 如果栈顶元素的优先级大于等于当前操作符。则从数字栈中依次pop出两个元素v1, v2 ;然后从字符栈中pop出一个字符 ,计算出v2、v1 在该运算中的值val。
* 将val压入数字栈顶,将当前的操作符压入栈顶
* 如果栈顶元素的优先级小于当前的操作符,则将当前操作符压入操作符栈
* 遍历完整个字符串后。将temp压入到数字栈中 每次从操作符栈中弹出一个运算符,从数字栈中弹出依次弹出两个值 v1, v2。 v2, v1 按照弹出的计算符运算之后得到v,将v压入数字栈
* 直到操作符栈为空,则数字栈栈顶的元素则为最终的值。
*
* @param str
* @return
*/
public int calculate(String str) {
if (str == null || str.length() <= 0) {
return 0;
}
int temp = 0;
for (int i = 0; i < str.length(); i++) {
char curCh = str.charAt(i);
/**
* 如果是数字
*/
if (isNumber(curCh)) {
temp = temp * 10 + Character.getNumericValue(curCh);
continue;
}
numberStack.push(temp);
temp = 0;
/**
* 如果栈为空,则直接压入栈
*/
if (operatorStack.isEmpty()){
operatorStack.push(curCh);
continue;
}
char topOperator = operatorStack.peek();
int topPriority = getPriority(topOperator);
int curPriority = getPriority(curCh);
//如果操作符栈栈顶的操作符的优先级高于当前操作符的优先级,则依次将数据栈中pop出两个数字,按照操作符栈顶的元素进行运算,并且将运算结果
//压入到数据栈中,然后将当前操作符压入到
if (topPriority >= curPriority){
Character operator = operatorStack.pop();
Integer num1 = numberStack.pop();
Integer num2 = numberStack.pop();
int res = calculate(num1, num2, operator);
numberStack.push(res);
operatorStack.push(curCh);
continue;
}
//如果当前操作符的优先级高于操作栈顶的操作符的优先级,则将操作符压入操作数栈中
operatorStack.push(curCh);
}
//遍历完成之后,每次从操作符栈中弹出一个操作符,从数据栈中依次弹出两个数字,进行运算,然后将运算结果压入数据栈中
numberStack.push(temp);
while (!operatorStack.isEmpty()){
Character operator = operatorStack.pop();
Integer num1 = numberStack.pop();
Integer num2 = numberStack.pop();
int res = calculate(num1, num2, operator);
numberStack.push(res);
}
return numberStack.pop();
}
private int calculate(int num1, int num2, char operation){
switch (operation){
case '+':
return num1 + num2;
case '-':
return num2 - num1;
case '*':
return num1 * num2;
case '/':
return num2 / num1;
default:
System.out.println("错误的输入");
}
throw new RuntimeException("错误的输入");
}
/**
* 判断是否是数字
*
* @param cur
* @return
*/
private boolean isNumber(char cur) {
return Character.isDigit(cur);
}
/***
* 获取操作符的优先级, 数字越大优先级越高
* @param ch
* @return
*/
private int getPriority(char ch){
if (ch == '+' || ch == '-'){
return 1;
}
if (ch == '*' || ch == '/'){
return 2;
}
return -1;
}
public static void main(String[] args) {
System.out.println();
BasicCalculator2 calculator = new BasicCalculator2();
int res = calculator.calculate("12+3*5+4/4-6");
System.out.println(res);
}
}