Problem
Given a string s
representing a valid expression, implement a basic calculator to evaluate it, and return the result of the evaluation.
Note: You are not allowed to use any built-in function which evaluates strings as mathematical expressions, such as eval()
.
Examples
Example 1:
|
|
Example 2:
|
|
Example 3:
|
|
Constraints
1 <= s.length <= 3 * 10^5
s
consists of integers and operators('+', '-', '*', '/')
separated by some number of spaces.s
represents a valid expression.- All the integers in the expression are non-negative integers in the range
[0, 2^31 - 1]
. - The answer is guaranteed to fit in a 32-bit integer.
Solution
Method 1 - Using Stack for Operands 🥈
If all operators had the same priority, we could sequentially calculate each number and operator, saving only the latest result. However, to account for operator priorities (’*
’ and ‘/
’ having higher priority than ‘+’ and ‘-’), we utilise a stack to track encountered numbers.
A straightforward algorithm is:
- Use global variables:
prevOpr
to remember the last operator encountered,num
for the current number, and a stack to hold numbers. - Traverse the string character by character following these rules:
- If the current character is a blank, simply move to the next step.
- If it’s a digit, build the number using a while loop to capture the full digit sequence.
- Otherwise, it’s an operator, indicating completion of a new number (or the end of the string). Process the number with
prevOpr
based on these rules:- If
prevOpr
is ‘+’ or ‘-’, we may encounter operator with higher priority in the future, so appendnum
or-num
to the stack:1 2 3 4 5 6
case '+': stack.push(num); break; case '-': stack.push(-num); break;
1 2 3 4 5 6 7 8 9 10 11 12 13
- If `prevOpr` is '`*`' or '`/`', execute the operation immediately, pop the last number from the stack, apply the operation, and push the result back to the stack: ```java case '*': stack.push(stack.pop() * num); break; case '/': stack.push(stack.pop() / num); break; ``` - At last, we have a stack containing a couple of numbers and all of them have the same operator '+'. Finally, sum up all numbers in the stack and return the result:: `while(!stack.isEmpty())res += stack.pop();`
- If
Initialise prevOpr
to ‘+’ for the first number:
|
|
Add an extra ‘+’ to the end of the string to ensure the last number is processed. (as when the last number is added, the prevOpr
still needs to execute on it):
|
|
Code
|
|
Method 2 - Without Using Stack 🏆
A further insight is that we can always sum all stack numbers except the latest one without affecting the result. Thus, we only need two variables instead of a stack:
prevNum
for the sum of all numbers except the latest one (to be added to the final result after the loop).num
for the latest number being processed.
Code
|
|
Method 3 - Without Modifying Input String, i.e. without s+"+"
Code
|
|