Implement a basic calculator to evaluate a simple expression string.
The expression string may contain open ( and closing parentheses ), the plus + or minus sign -, non-negative integers and empty spaces .
Input: “(1+(4+5+2)-3)+(6+8)”
Output: 23
hard难度的题,其实观察发现hard的题往往最初思路的构造并不难,难在实现过程中会有很多的情况需要考虑;
这道题思路其实是很好寻找的,表达式中括号内部必然也是一个完整的算式,所以很容易想到使用递归的思路去解决,对于每一个括号我们将括号内部的字符串作为新的参数进行调用,就可以将一对括号的表达式转化成一个具体的数值。
细节上有一点点复杂,为了方便首先先采用 str.replaceAll(” “,”“)将空格去掉,那么我们只剩下三种可能:
1.’(’ :这就标志着一次递归调用的开始,我们发现一次递归调用必然是以一个括号开始一个括号结束的,那么我们可以将参数设计成开始的index,在每次扫描到’(‘时候发起新的调用,然后调用完成之后将i变成子调用结束之后的位置;
2.’)’标志着当前调用层的结束
3.’数字’,加入到cur当前的数字值中
4.’符号’,意味着上一个符号+数字的组合已经完成,所以将结果进行计算,并且重新初始化符号和数值
//递归版本
class Solution {
char[] a;
String s;
public int calculate(String str) {
s = str.replaceAll(" ","");
a = s.toCharArray();
return cal(0)[0];
}
public int[] cal(int s){
int res = 0;
int cur = 0;
int sign = 1;
int[] data = new int[2];
for(int i = s;;i++){
if(i>=a.length || a[i] == ')'){
res += cur * sign;
data[0] = res;
data[1] = i;
return data;
}
if(a[i] == '+' || a[i] =='-'){
res += sign * cur;
cur = 0;
sign = a[i]=='+'? 1:-1;
}
else if(a[i]=='('){
int[] part = cal(i+1);
i = part[1];
res+=sign*part[0];
}
else{
cur = cur*10 + (a[i]-'0');
}
}
}
}
因为递归调用本质上是用jvm的栈来存储调用顺序的,所以我们自然可以自己手动用栈来实现计算,整体思路与上面类似,在遇到一个(的时候意味着我们需要进入更高一级的表达式,用栈存储当前级的计算结果和符号,进行下一级的运算;在遇到‘)’的时候就意味着我们这一级已经完成了,将该级的结果与栈顶的上一级结果进行合成;
class Solution {
public int calculate(String s) {
s = s.replaceAll(" ","");
int layer = 0;
int num = 0;
int sign = 1;
char[] a = s.toCharArray();
Stack<Integer> stack = new Stack<>();
for(char c:a){
if(c=='('){
\\进入新的一层,将当前层的现场放入栈中保留
stack.push(layer);
stack.push(sign);
sign = 1;
layer = 0;
}
else if(c=='+' || c=='-'){
layer += num * sign;
num = 0;
sign = c=='+'? 1:-1;
}
else if(c==')'){
\\当前层结束,返回之前的层;
layer += num * sign;
num = 0;
layer = layer * stack.pop() + stack.pop();
}
else num = num*10 + (c-'0');
}
**\\注意这一步很关键,对于单层没有右括号的情况,最后一项并不会在循环中进行运算**
return layer+num*sign;
}
}