Code Logo

Basic Calculator III

Published at23 Jul 2026
Hard 5 views
Like0

Evaluate an arithmetic expression with integers, operators +, -, *, /, and parentheses (). The expression is always valid. Integer division truncates toward zero.

This extends Basic Calculator II by adding nested parentheses. Two stacks handle this: one for operands, one for operators. When an operator arrives, while the top of the operator stack has equal or higher precedence, pop and compute. Parentheses mark expression boundaries: push ( to operator stack, and when ) is encountered, compute until matching (. This is the shunting-yard algorithm adapted for evaluation.

The two-stack approach (one for operands, one for operators) handles the full arithmetic expression evaluation. Numbers are pushed onto the operand stack. Operators are pushed onto the operator stack, but only after all operators with higher or equal precedence have been popped and evaluated. Parentheses create a sub-expression boundary: when an opening parenthesis is encountered, it is pushed as a marker. When a closing parenthesis is encountered, all operators until the matching opening parenthesis are evaluated.

This is the standard shunting-yard algorithm adapted for direct evaluation. Understanding this algorithm is essential for building expression evaluators and interpreters. The same technique applies to evaluating reverse Polish notation and Boolean expressions.

Integer division must truncate toward zero, which affects how negative results are computed. The expression is guaranteed to be valid and will not contain division by zero. Operators are evaluated with standard precedence rules: multiplication and division before addition and subtraction. Parentheses override precedence. This problem is commonly asked in senior-level interviews as it tests understanding of expression parsing, precedence, and stack-based evaluation.

Negative numbers are handled by the subtraction operator: when a minus sign is encountered, the next number is subtracted rather than added. Consecutive operators like 1--2 are not allowed in this problem. The input is always well-formed.

Example Input & Output

Example 1
Input
1+2*3
Output
7
Explanation

2*3=6, 1+6=7.

Example 2
Input
(1+2)*3
Output
9
Explanation

Parentheses first.

Example 3
Input
(2+3)*(4+5)
Output
45
Explanation

Nested parentheses.

Algorithm Flow

Recommendation Algorithm Flow for Basic Calculator III

Solution Approach

Evaluate a mathematical expression string containing +, -, *, /, parentheses, and non-negative integers. Use two stacks: one for numbers and one for operators. Process the expression left to right, handling operator precedence by evaluating higher-precedence operators (*, /) before lower ones (+, -). When encountering ')', evaluate until '('.

function calculate(s) {
  var nums = [], ops = [];
  for (var i = 0; i < s.length; i++) {
    var c = s[i];
    if (c === ' ') continue;
    if (c >= '0' && c <= '9') {
      var n = 0;
      while (i < s.length && s[i] >= '0' && s[i] <= '9') { n = n * 10 + parseInt(s[i]); i++; }
      i--; nums.push(n);
    } else if (c === '(') { ops.push(c); }
    else if (c === ')') {
      while (ops.length && ops[ops.length - 1] !== '(') evalOp();
      ops.pop();
    } else {
      while (ops.length && precedence(ops[ops.length - 1]) >= precedence(c)) evalOp();
      ops.push(c);
    }
  }
  while (ops.length) evalOp();
  return nums.pop();
  function evalOp() {
    var b = nums.pop(), a = nums.pop(), op = ops.pop();
    if (op === '+') nums.push(a + b);
    else if (op === '-') nums.push(a - b);
    else if (op === '*') nums.push(a * b);
    else nums.push(Math.floor(a / b));
  }
  function precedence(op) { return op === '*' || op === '/' ? 2 : 1; }
}

The algorithm evaluates all sub-expressions when a closing parenthesis is encountered, respecting operator precedence throughout. Numbers are parsed as multi-digit integers.

Time O(n), Space O(n).

Best Answers

java
import java.util.*;
class Solution {
    public int solution(String s) {
        Stack<Integer> nums = new Stack<>();
        Stack<Character> ops = new Stack<>();
        int i = 0;
        while (i < s.length()) {
            char ch = s.charAt(i);
            if (ch >= '0' && ch <= '9') {
                int num = 0;
                while (i < s.length() && s.charAt(i) >= '0' && s.charAt(i) <= '9') { num = num * 10 + (s.charAt(i) - '0'); i++; }
                nums.push(num); continue;
            } else if (ch == '(') { ops.push(ch); }
            else if (ch == ')') {
                while (!ops.isEmpty() && ops.peek() != '(') calc(nums, ops);
                ops.pop();
            } else if ("+-*/".indexOf(ch) >= 0) {
                while (!ops.isEmpty() && prec(ops.peek()) >= prec(ch)) calc(nums, ops);
                ops.push(ch);
            }
            i++;
        }
        while (!ops.isEmpty()) calc(nums, ops);
        return nums.pop();
    }
    void calc(Stack<Integer> nums, Stack<Character> ops) {
        int b = nums.pop(), a = nums.pop();
        char op = ops.pop();
        if (op == '+') nums.push(a + b); else if (op == '-') nums.push(a - b);
        else if (op == '*') nums.push(a * b); else nums.push(a / b);
    }
    int prec(char op) { return op == '*' || op == '/' ? 2 : op == '(' ? 0 : 1; }
}