题目主要信息
1、给定一个表达式求值
2、字符串中的有效字符包括[‘0’-‘9’],‘+’,‘-’,‘(’, ‘)’
3、字符串一定合法
4、可能出现多个数字连在一起组成多位数
5、可能出现负数
方法一:利用栈求解
具体方法
我们可以用o1来储存当前符号,具体定义为
+,o1=1,-,o1=-1
我们通过表达式res=num1+o1×num2来保存当前算式,其中num1为已经计算部分的值,而num2是正在计算部分的值,num1和num2中间由+-隔开
当遇到数字时,我们直接获取数字,并且计算o2,获得num2
当遇到+-时,代表前面的公式已经计算完毕,计算num1,并更新o1,o2,num2
当遇到左括号时,我们要把现在所有结果入栈,并且重置参数
当遇到右括号时,我们要获得当前数字来更新num2
Java代码
import java.util.*;
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param s string字符串
* @return int整型
*/
public int calculate (String s) {
// write code here
Stack<Integer> stack = new Stack<Integer>();
// sign 代表正负
int sign = 1, res = 0;
int length = s.length();
for (int i = 0; i < length; i++) {
char ch = s.charAt(i);
if (Character.isDigit(ch)) {
int cur = ch - '0';
while (i + 1 < length && Character.isDigit(s.charAt(i + 1)))
cur = cur * 10 + s.charAt(++i) - '0';
res = res + sign * cur;
} else if (ch == '+') {
sign = 1;
} else if (ch == '-') {
sign = -1;
} else if (ch == '(') {
stack.push(res);
res = 0;
stack.push(sign);
sign = 1;
} else if (ch == ')') {
res = stack.pop() * res + stack.pop();
}
}
return res;
}
}
复杂度分析
- 时间复杂度:,时间复杂度和表达式长度正相关
- 空间复杂度:,需要一个栈,长度和表达式长度正相关
方法二:逆波兰表达式
具体方法
这道题可以通过逆波兰表达式来进行计算。
逆波兰计算器的原理是使用逆波兰表达式来计算出表达式的值,我们人类能够熟练使用的是中缀表达式,比如2×(9+6/3-5)+4就是一个中缀表达式,但是看到上面的简单计算器就知道处理起来很麻烦。于是有一种逆波兰计算器,计算是在逆波兰表达式(也叫做后缀表达式)的基础上。
逆波兰计算器的计算过程为:从左到右扫描后缀表达式,遇到数字就入栈,遇到操作符就从栈弹出两个数字,然后计算得到的值继续入栈,继续扫描表达式,直到扫描完毕得到结果。
从逆波兰计算器的扫描过程可以看到,过程特别简单,代码写起来也比较容易。但现在的难点在于:如何把中缀表达式转成后缀表达式?
这个过程已经有大神给出来了,我们记下来即可:
1、初始化两个栈:运算符栈s1和存储中间结果的栈s2;
2、从左到右扫描中缀表达式;
3、遇到操作数时,压入到栈s2;
4、遇到运算符时:
1)如果s1为空或s1栈顶为左括号"(",则压入到s1;
2)不满足1),则和s1栈顶运算符比较优先级,高于,则压入s1;
3)不满足1)和2),弹出s1栈顶运算符并压入到s2,再次回到2)。
5、遇到右括号")“时,依此弹出s1并压入s2,直到遇到左括号”)"为止,此时丢掉一对括号;
6、重复2-5,直到扫描完毕;
7、将s2栈弹出压入到s1,然后s1弹出全部,弹出的顺序即为后缀表达式。
逆波兰表达式应该现在是个常见方法了,大家可以记下来,在这个基础上进行简单修改即可。
Java代码
import java.util.*;
class Solution {
Map<Character, Integer> map;
public int calculate(String s) {
map = new HashMap();
map.put('+', 1);
map.put('-', 1);
map.put('*', 2);
map.put('/', 2);
map.put('(', 3);
s = s.replaceAll(" ", "");
String s1 = transfer(s);
// System.out.println(s1);
return cal(s1.split(" "));
}
String transfer(String s){
StringBuilder sb = new StringBuilder();
Deque<Character> stack = new LinkedList<>();
char[] cs = s.toCharArray();
int n = cs.length;
if(n!=0 && !Character.isDigit(cs[0])){
sb.append("0 ");
}
int temp = 0;
for(int i=0; i<n; i++){
char c = cs[i];
if(Character.isDigit(c)){
temp = temp*10 + (c-'0');
if(i==n-1 || !Character.isDigit(cs[i+1])){
sb.append(temp);
sb.append(" ");
temp = 0;
}
}else if(c=='('){
stack.push(c);
}else if(c==')'){
while(stack.peek()!='('){
sb.append(stack.pop());
sb.append(" ");
}
stack.pop();
}else{
while(!stack.isEmpty() && map.get(c)>=map.get(stack.peek())){
sb.append(stack.pop());
sb.append(" ");
}
stack.push(c);
}
}
while(!stack.isEmpty()){
sb.append(stack.pop());
sb.append(" ");
}
return sb.toString();
}
int cal(String[] tokens) {
Deque<Integer> stack = new LinkedList<>();
int n = tokens.length;
String s;
for(int i=0;i<n;i++){
s = tokens[i];
if(s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")){
int a = stack.pop();
int b = stack.pop();
stack.push(calculate(a, b, s));
}else{
stack.push(Integer.parseInt(s));
}
}
return stack.peek();
}
int calculate(int a,int b,String s){
if(s.equals("+")){
return a+b;
}
if(s.equals("-")){
return b-a;
}
if(s.equals("*")){
return a*b;
}
return b/a;
}
}
复杂度分析
- 时间复杂度:,时间复杂度和表达式长度正相关
- 空间复杂度:,需要一个栈,长度和表达式长度正相关