This problem is similar to the general computational solution, which can be solved by stack. When optimizing, we can take advantage of the particularity of the problem itself.

## Original title

Implement a basic calculator to calculate the value of a simple string expression.

String expressions contain only non negative integers, +, -, *, / operators and spaces 。 Integer division preserves only the integer part.

Example 1:

```
Input: "3 + 2 * 2"
Output: 7
```

Example 2:

```
Input: "3 / 2"
Output: 1
```

Example 3:

```
Input: "3 + 5 / 2"
Output: 5
```

explain:

- You can assume that the given expressions are valid.
- Do not use the built-in library function eval.

Original title URL: https://leetcode-cn.com/probl…

## answer

### Stack

The first thing I think of in this problem is to use two stacks to store operators and numbers. When traversing, first put the corresponding characters on the stack. When encountering high-level operations (for example, / is higher than +, -), directly put them on the stack, otherwise press out the number for calculation.

Let’s look at the code:

```
class Solution {
public int calculate(String s) {
//Symbol stack
Stack<Character> signStack = new Stack<>();
//Digital stack
Stack<Integer> numStack = new Stack<>();
//Used to store the level of the operator
Map<Character, Integer> signLevelMap = new HashMap<>(6);
//+, - are low-level operators
signLevelMap.put('+', 1);
signLevelMap.put('-', 1);
//*, / are high-level operators
signLevelMap.put('*', 2);
signLevelMap.put('/', 2);
//Traversal
int tempNum = 0;
for (char charS : s.toCharArray()) {
//Skip spaces
if (charS == ' ') {
continue;
}
Integer level = signLevelMap.get(charS);
//If the current is a number
if (level == null) {
tempNum = charS - '0' + tempNum * 10;
continue;
}
//If the current is a symbol, press the previous number into numstack
numStack.push(tempNum);
tempNum = 0;
//If there is no previous symbol, the current symbol is directly pushed onto the stack
if (signStack.empty()) {
signStack.push(charS);
continue;
}
//If there is a symbol before, look at the two levels
Character signBefore = signStack.peek();
int levelBefore = signLevelMap.get(signBefore);
//If current level > previous level
if (level > levelBefore) {
//Pushes the current symbol directly onto the stack
signStack.push(charS);
continue;
}
//If the current level < = the previous level, the previous symbol can be calculated directly
while (level <= levelBefore) {
signStack.pop();
int num2 = numStack.pop();
int num1 = numStack.pop();
int result = 0;
switch (signBefore) {
case '+':
result = num1 + num2;
break;
case '-':
result = num1 - num2;
break;
case '*':
result = num1 * num2;
break;
case '/':
result = num1 / num2;
break;
}
//Push the result into the stack again
numStack.push(result);
if (signStack.empty()) {
break;
}
signBefore = signStack.peek();
levelBefore = signLevelMap.get(signBefore);
}
//Press the symbol into the signstack
signStack.push(charS);
}
//Press the last number into numstack
numStack.push(tempNum);
//Calculate all data in the stack
int result = 0;
while (!signStack.empty()) {
char sign = signStack.pop();
int num2 = numStack.pop();
int num1 = numStack.pop();
switch (sign) {
case '+':
result = num1 + num2;
break;
case '-':
result = num1 - num2;
break;
case '*':
result = num1 * num2;
break;
case '/':
result = num1 / num2;
break;
}
//Push the result into the stack again
numStack.push(result);
}
return numStack.pop();
}
}
```

The submission was successful, but the execution time was only defeated`43.97%`

Java submission records can certainly be optimized.

### Combined with topic characteristics

The reason why the above is slow should be related to pressing the stack and entering the stack, because it is equivalent to repeatedly calculating and re traversing the content that has been traversed. Is there any way to directly traverse and end at one time?

The title says only`+、-、*、/`

Four operators, if yes`+、-`

, cannot be evaluated directly because the next operator may be`*、\`

, those with higher grades will be given priority. But if so`*、/`

, it can be calculated directly, because there is no higher level than them.

So how to solve it`+、-`

What about the direct calculation? Actually, we can`+、-`

The following expressions are treated as a whole until they are encountered again`+、-`

。 For this whole, there are two situations:

- Just a number
- from
`*、/`

In this case, the result can be calculated directly, which is also a number.

In this way, we can ensure that we can directly calculate the answer by traversing it once. Next, look at the code:

```
class Solution {
public int calculate(String s) {
//Find the first number first
int[] resultArray = findNum(0, s);
int result = resultArray[0];
//Start traversal
for (int i = resultArray[1] + 1; i < s.length(); i++) {
char charS = s.charAt(i);
//Skip spaces
if (charS == ' ') {
continue;
}
//*, / calculated directly
if (charS == '*' || charS == '/') {
resultArray = findNum(i + 1, s);
i = resultArray[1];
result = (charS == '*') ? (result * resultArray[0]) : (result / resultArray[0]);
continue;
}
//+, - take it as a whole and calculate it again
if (charS == '+' || charS == '-') {
resultArray = findWholeNum(i + 1, s);
i = resultArray[1];
result = (charS == '+') ? (result + resultArray[0]) : (result - resultArray[0]);
}
}
return result;
}
/**
*Treat the following expression as a whole.
*Returns an array. The subscript 0 represents the result of the expression, and the subscript 1 represents the subscript at the end of the expression.
*/
public int[] findWholeNum(int index, String s) {
//First number found
int[] resultArray = findNum(index, s);
int result = resultArray[0];
int newIndex = resultArray[1] + 1;
for (; newIndex < s.length(); newIndex++) {
char charS = s.charAt(newIndex);
if (charS == ' ') {
continue;
}
//It ends when you encounter +, -
if (charS == '+' || charS == '-') {
break;
}
if (charS == '*' || charS == '/') {
resultArray = findNum(newIndex + 1, s);
newIndex = resultArray[1];
result = (charS == '*') ? (result * resultArray[0]) : (result / resultArray[0]);
}
}
resultArray = new int[]{result, newIndex - 1};
return resultArray;
}
/**
*Find the next number.
*Returns an array. The subscript 0 represents the value of a number, and the subscript 1 represents the subscript at the end of a number.
*/
public int[] findNum(int index, String s) {
int num = 0;
int newIndex = index;
for (; newIndex < s.length(); newIndex++) {
char charS = s.charAt(newIndex);
if (charS == ' ') {
continue;
}
if (charS > '9' || charS < '0') {
break;
}
num = charS - '0' + num * 10;
}
return new int[]{num, newIndex - 1};
}
}
```

Submit OK and the execution time is over`96.66%`

Java submission records, which should also be OK.

## summary

The above is my answer to this question. I don’t know if you understand it. This problem can be solved by stack or more efficiently by taking advantage of the particularity of the problem itself.

If you are interested, you can visit my blog or follow my public number and headline number. There may be an unexpected surprise.

https://death00.github.io/

Public account: Jiancheng Road