Implement a basic calculator to evaluate a simple expression string.
The expression string contains only non-negative integers, +
, -
, *
, /
operators and empty spaces . The integer division should truncate toward zero.
Example 1:
Input: "3+2*2" Output: 7
Example 2:
Input: " 3/2 " Output: 1
Example 3:
Input: " 3+5 / 2 " Output: 5
这一题和Basic Calculator的不同在于Basic Calculator没有乘除法,但有括号,这里有乘除法,没有括号。这题的思路就变得比较不一样了。这一题,我的做法的思路简单来说就是加减法直接运算进结果,而连续的乘除法字符串当成一个整体进行处理。
举个例子: 1 + 2 + 3 * 4 * 5 / 6 - 7 - 8 * 9
整个算法的运算流程是
1 + 2 + 3 * 4 * 5 / 6 - 7 - 8 * 9
=> 3 + 3 * 4 * 5 / 6 - 7 - 8 * 9
=> 3 + 12 * 5 / 6 - 7 - 8 * 9
=> 3 + 60 / 6 - 7 - 8 * 9
=> 3 + 10- 7 - 8 * 9
=> 13 - 7 - 8 * 9
=> 6 - 8 * 9
=> 6 - 72 => -66
从这个过程里面我们可以看到,我们需要一个变量存放目前的计算结果,同时一个变量去存放遇到连续乘除的时候的临时结果。这个算法里,运算是在遇到数字的情况发生,遇到计算符号就只做某种程度的标记。流程如下:
1. 如果遇到加号或者减号,就标记接下来的数字是需要进行加法或者减法处理(用一个变量sign来表示,sign初始为1,实际就相当于在给定式子前面加了一段 0 + ,也就是 1 * 2 + 3 变成了 0 + 1 * 2 + 3)
2. 如果遇到乘号或者除号,就把之前记录下来的连续乘除的临时结果(也可能是某一个数字),标记为乘数或者被除数
3. 如果遇到数字,需要同时考虑到之前记录下来的情况,以及之后还会遇到的运算符。如果有记录乘数或者被除数,就利用那个乘数和被除数对当前数字进行计算。然后还需要判断之后将要遇到的运算符,如果是加号或者减号,这个数字或者连续运算的结果就会直接根据再之前遇到的加减号直接与目前的计算结果进行计算;但如果是乘除号,就表示当前的乘除连续计算并未结束,这个结果会被放到存放连续乘除的临时结果,这个临时结果,会根据接下来(2遇到)的运算符而被判断为被乘数或者被除数。
根据上述算法,给出代码如下:
public int calculate(String s) {
int res = 0;
int sign = 1;
int prevMulti = 1;
Integer prevDiv = null;
int num = 0;
s = s.replace(" ", "");
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (Character.isDigit(c)) {
num = 0;
while (i < s.length() && Character.isDigit(s.charAt(i))) {
num = num * 10 + s.charAt(i) - '0';
i++;
}
num *= prevMulti;
if (prevDiv != null) num = prevDiv / num;
prevMulti = 1;
prevDiv = null;
if (i == s.length() || (s.charAt(i) != '*' && s.charAt(i) != '/' )) {
res += sign * num;
}
if (i < s.length()) i--;
} else if (c == '+') {
sign = 1;
} else if (c == '-') {
sign = -1;
} else if (c == '*') {
prevMulti = num;
} else if (c == '/') {
prevDiv = num;
}
}
return res;
}