问题描述
小F面临一个编程挑战:实现一个基本的计算器来计算简单的字符串表达式的值。该字符串表达式有效,并可能包含数字(0-9)、运算符+、-及括号()。注意,字符串中不包含空格。除法运算应只保留整数结果。请实现一个解析器计算这些表达式的值,且不使用任何内置的eval函数。
测试样例
样例1:
输入:
expression = "1+1"输出:2
样例2:
输入:
expression = "3+4*5/(3+2)"输出:7
样例3:
输入:
expression = "4+2*5-2/1"输出:12
样例4:
输入:
expression = "(1+(4+5+2)-3)+(6+8)"输出:23
样例5:
输入:
expression = "2*(5+5*2)/3+(6+8*3)"输出:40
Solution
直接下手这个问题显然是很困难的,但是我们知道如果将表达式变成后缀表达式的话,那么使用栈就可以很轻松的解决这个问题了,那么我们知道后缀表达式怎么运算,只需要将这个表达式转换成后缀表达式就可以了。
转换成后缀表达式:
- 遇到左括号时,将其压入栈中
- 遇到右括号时,开始弹出栈中的运算符,并将其添加到结果列表中,直到遇到左括号
- 对于加号和减号,只在栈顶不是左括号时才将其压入栈中
- 对于乘号和除号,只在栈顶是左括号或者栈为空时才将其压入栈中
这样,就可以保证乘除运算的优先级高于加减运算
后面的话,就是正常的计算后缀表达式的过程了,每次取出两个数和一个运算符进行计算即可
Java代码实现
import java.util.*;
public class Main {
public static int solution(String expression) {
List<String> ex = get(expression);
Stack<Integer> stk = new Stack<>();
for (String s : ex) {
if (Character.isDigit(s.charAt(0))) {
int num = Integer.parseInt(s);
stk.push(num);
} else {
int b = stk.pop();
int a = stk.pop();
switch (s) {
case "+":
stk.push(a + b);
break;
case "-":
stk.push(a - b);
break;
case "*":
stk.push(a * b);
break;
case "/":
stk.push(a / b);
break;
}
}
}
return stk.peek();
}
private static List<String> get(String s) {
Stack<Character> stk = new Stack<>();
List<String> ans = new ArrayList<>();
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (Character.isDigit(ch)) {
StringBuilder tmp = new StringBuilder();
while (i < s.length() && Character.isDigit(s.charAt(i))) {
tmp.append(s.charAt(i));
i++;
}
ans.add(tmp.toString());
i--;
} else if (ch == '(') {
stk.push(ch);
} else if (ch == ')') {
while (!stk.isEmpty() && stk.peek() != '(') {
ans.add(String.valueOf(stk.pop()));
}
stk.pop();
} else if (ch == '+' || ch == '-') {
while (!stk.isEmpty() && stk.peek() != '(') {
ans.add(String.valueOf(stk.pop()));
}
stk.push(ch);
} else if (ch == '*' || ch == '/') {
while (!stk.isEmpty() && stk.peek() != '(' && stk.peek() != '+' && stk.peek() != '-') {
ans.add(String.valueOf(stk.pop()));
}
stk.push(ch);
}
}
while (!stk.isEmpty()) {
char c = stk.pop();
if (c != '(') {
ans.add(String.valueOf(c));
}
}
return ans;
}
public static void main(String[] args) {
// You can add more test cases here
System.out.println(solution("1+1") == 2);
System.out.println(solution("3+4*5/(3+2)") == 7);
System.out.println(solution("4+2*5-2/1") == 12);
System.out.println(solution("(1+(4+5+2)-3)+(6+8)") == 23);
}
}
时空复杂度
时间复杂度: O(n)
空间复杂度: O(n)
总结与思考
这是一个比较常用的问题,算法方面也比较简单,只是栈的简单应用,但是代码方面会比较多,比较锻炼代码能力