题目描述
给你一个字符串表达式 s ,请你实现一个基本计算器来计算并返回它的值。
示例:
输入:s = “(1+(4+5+2)-3)+(6+8)”
输出:23
提示:
1 <= s.length <= 3 * 105
s 由数字、’+’、’-’、’(’、’)’、和 ’ ’ 组成
s 表示一个有效的表达式
解法:
这里参考了leetcode Maple597同学的解法,不使用堆栈,使用一种类似编译原理的递归解法。
任何表达式都可看做形如:a+b+c+d
的形式。例如1+2+3+4
。上面给出的示例(1+(4+5+2)-3)+(6+8)
可以看成a+b
,其中a=1+(4+5+2)-3
,b=6+8
。由于a
内 存在括号,a
又可以被拆封为三部分c+d+e
,c=1
,d=4+5+2
,e=-3
。这是个递归过程。
核心操作(new_res = operateUnit(pre_res)
):
找到+ -符号,将之前的结果加(减)到 + -符号后面的那个数上。例如1+2+3+4
找打1和2中间的+,将之前的结果1加到2上得到新结果3。我们可以将1+2+3+4
前面加上+:+1+2+3+4
这样就可以从左边第一个字符开始作用operateUnit函数。operateUnit:
//operateUnit功能:找到+ -符号,将之前的结果加(减)到 + -符号后面的那个数上
long long operateUnit(long long pre){
while(i<n&&s[i]==' ') i++;
if(s[i]=='+'){
i++;
pre+=selectElem();//pre=pre+后面一个数字。但是, +-之后也可能是'+','-','(',必须分类计算
}
else if(s[i]=='-'){
i++;
pre-=selectElem();
}
return pre;
}
+ - 符号后面可能是’+’,’-’,’(’,‘数字’。必须分类计算。这里使用long long selectElem()
函数。该函数返回+ -符号后面的数字和,例如1+(2+6)+1
,i=2
时,selectElem
应该返回8
。
这里直接贴出全部代码:
class Solution {
public:
int i;
int n;
string s;
//只要遇到+-则进入该函数,进行基本单元+-运算
//任何表达式都可看做 a+b+c+d+e 的结构,以a为例,a可能不是数字而是(f+g+h)的表达式结构,这又可以用以下函数进行处理,这是递归过程
long long operateUnit(long long pre){
while(i<n&&s[i]==' ') i++;
if(s[i]=='+'){
i++;
pre+=selectElem();//pre=pre+后面一个数字。但是, +-之后也可能是+- (,必须分类计算
}
else if(s[i]=='-'){
i++;
pre-=selectElem();
}
return pre;
}
//计算+-符号后面的一个数字
long long selectElem(){
while(i<n&&s[i]==' ') i++;
//如果是 ( ,需要进行递归计算
if(s[i]=='('){
return bracketsCompute();
}
//+-符号后面又出现+-符号 。或凭空出现+-符号(如 1++2、+(1+2)、(+1+2) )这种情况不处理,这里默认表达式合法
else if(s[i]=='+'||s[i]=='-'){
return 0;
}
//如果是数字,直接将该值返回
long long temp=0;
if(s[i]>='0'&&s[i]<='9'){
while(i<n&&s[i]>='0'&&s[i]<='9'){
temp = temp*10+s[i++]-'0';
}
}
return temp;
}
//括号内计算和外面的 a+b+c+d+e 计算方法一样
long long bracketsCompute(){
i++;
//关键操作:----------------------
long long res=selectElem();//'('的下一个一定是数字或'('
while(i<n&&s[i]!=')'){
res = operateUnit(res);
}
//关键操作结束--------------------
i++;
return res;
}
int calculate(string s) {
i=0;
this->s=s;
n=s.size();
//关键操作:---------------------
long long res=selectElem();//表达式头部是一定以数字或左括号开始,可以认为是+开始的,因此调用selectElem计算出第一个值,调用selectElem后,i一定定位在+-符号上
while(i != n){
res = operateUnit(res);
}
//关键操作结束------------------
return res;
}
};