Last Updated: April 1, 2026
We need to evaluate a mathematical expression containing the four basic arithmetic operators (+, -, *, /) along with spaces and non-negative integers. No parentheses this time, which simplifies things compared to Basic Calculator. But the real challenge here is operator precedence: multiplication and division must be evaluated before addition and subtraction.
Consider 3+2*2. If we just evaluate left to right, we get (3+2)*2 = 10, which is wrong. The correct answer is 3+(2*2) = 7 because * binds tighter than +.
So the core question is: how do we respect operator precedence in a single pass through the string? The key observation is that when we see a + or -, we cannot immediately compute because the next number might be involved in a * or /. But when we see * or /, we can compute immediately because nothing has higher precedence. This asymmetry is what drives the solution.
1 <= s.length <= 3 * 10^5 → We need an O(n) solution. Parsing the string multiple times or using heavy recursion with repeated substring operations would be too slow.s consists of digits, +, -, *, /, and spaces → We need to skip whitespace and parse multi-digit numbers.// rounds toward negative infinity, so we should use int(a / b) instead.The most natural way to handle operator precedence is to use a stack. The idea is simple: we process the expression left to right, and whenever we encounter + or -, we push the current number (with its sign) onto the stack. We defer the final summation until the end. But when we encounter * or /, we pop the top of the stack, compute immediately, and push the result back. This way, all multiplications and divisions are resolved as soon as they appear, while additions and subtractions are collected and summed at the end.
Why does this work? Because * and / only ever involve two operands: the number right before them (which is on top of the stack) and the number right after them (which we just parsed). By computing them immediately, we ensure they take precedence over the pending + and - operations waiting in the stack.
currentNum to build multi-digit numbers, and a variable prevOp set to '+' (because the first number is implicitly preceded by addition).currentNum by multiplying by 10 and adding the digit.prevOp:prevOp is '+', push currentNum onto the stack.prevOp is '-', push -currentNum onto the stack.prevOp is '*', pop the stack, multiply by currentNum, push the result.prevOp is '/', pop the stack, divide by currentNum (truncating toward zero), push the result.prevOp to the current operator, and reset currentNum to 0.The stack approach works well but we never look deeper than the top element. Since we only ever modify the top of the stack, we can replace it with just two variables and eliminate the extra space entirely.
Since there are no parentheses, we only have two levels of precedence: *// (high) and +/- (low). When we encounter * or /, we immediately compute with the previous number. When we encounter + or -, the previous number is "finalized" and can be added to the running result.
So we track two things: result (the accumulated sum of all finalized terms) and lastNum (the most recent term that might still be involved in a * or /). When we see + or -, we know lastNum is done, so we add it to result and start a new term. When we see * or /, we update lastNum by multiplying or dividing it with the next number.
This is essentially what the stack was doing, but since we only ever touch the top, two variables are enough.
The expression without parentheses can be thought of as a sum of "terms," where each term is a chain of multiplications and divisions. For example, 2+3*4/2-5 breaks down as (+2) + (+3*4/2) + (-5), which equals 2 + 6 + (-5) = 3. The variable lastNum accumulates the current term through any * or / operations, and result collects all finalized terms. When we see + or -, we know the current term is complete, so we flush lastNum into result and start a new term.
result = 0, lastNum = 0, currentNum = 0, and prevOp = '+'.currentNum.prevOp is '+', add lastNum to result, set lastNum = currentNum.prevOp is '-', add lastNum to result, set lastNum = -currentNum.prevOp is '*', set lastNum = lastNum * currentNum.prevOp is '/', set lastNum = lastNum / currentNum (truncate toward zero).prevOp to the current operator, reset currentNum = 0.result + lastNum (don't forget the last term).