【问题描述】 给定字符串str,str表示一个数学公式,里面含有运算符加减乘除、数字以及左右括号,返回公式的计算结果,如str="-1+2+3-4*(12-10)",返回-4。
一、递归求解
假设makevalue方法是一个递归求值过程,str="1+2*(3+4)-5"递归求值过程描述如下:
1.从字符串下标0位置开始遍历,如果遍历到’(‘则进入下一层递归;如果遍历到’)'或str遍历完,当前递归调用结束,并向上一递归调用过程返回递归调用结果——遍历结束位置和当前子串计算结果
2.如果遍历到运算符,直接从双端队列deque队尾入队
3.如果遍历到数字num,首先deque尾部元素opr出队,然后判断opr的运算符类型:若opr为’+‘或’-’,则num直接从队尾入队;若opr为’*‘或’/’,为保证其运算优先级,队尾元素pre出队,然后进行num=pre·opr·num运算,最后将运算结果num从队尾入队
递归过程说明:
刚开始进行遍历就进入递归调用makevalue(str,0),当遇到字符’(‘时,从makevalue(str,0)进入递归调用makevalue(str,4),当遇到’)'字符时,makevalue(str,4)递归调用结束,并向makevalue(str,0)返回两个递归调用结果:①makevalue(str,0)遍历结束位置8 ②当前字串的计算结果即"3+4"=7
用数组a[]=new int[2]来保存这两个结果,a[0]=8,用来告知上层调用其下一遍历位置应该从哪儿开始,a[1]=7,存储子串计算结果。对于makevalue(str,0),a[0]保存的是整个字符串str计算结果,a[1]保存的是整个字符串str的长度
子串计算结果说明:
因为每次遇到’(‘就进入下层递归调用,括号()中的子串结果是交给下层函数计算的,上层只需要接受下层返回的计算结果,所以对所有递归过程来说,都是不含字符’(‘和’)’,如对makevalue(str,0)来说,计算的实际上是1+2*7-5,因为(3+4)是交给下层makevalue(str,4)计算完成的,自己只需要接受下层返回的结果7
通过2、3步描述和以上说明,不难可以看出双端队列deque实际上保存的就是当前递归过程不包含字符’(‘和’)’,也不包含字符’*‘和’/’(见3)的字符串,只包含操作符‘+’、‘-’和操作数,即对makevalue(str,0)来说,deque={“1”,"+",“14”,"-",“5”},对makevalue(str,4)来说,deque={“3”,"+",“4”}
【算法描述】
public static int[] makeValue(char[] chas, int i) {
int val = 0;
int[] a = new int[2];
Deque<String> deque = new LinkedList<String>();
while (i < chas.length && chas[i] != ')') {
if (chas[i] >= '0' && chas[i] <= '9')
val = val * 10 + chas[i++] - '0';
else if (chas[i] != '(') {
//chas[i] in {+-*/}
addNum(deque, val);
deque.addLast(String.valueOf(chas[i++]));
val = 0;
} else {
a = makeValue(chas, i + 1);
val = a[0];
i = a[1] + 1;
}
}
addNum(deque, val);
return new int[]{
popNum(deque), i};
}
public static void addNum(Deque<String> deque, int num) {
if (!deque.