Problem: Basic Calculator II

Given a string `s` which represents an expression, evaluate this expression
and return its value.

The integer division should truncate toward zero.

You may assume that the given expression is always valid. All intermediate
results will be in the range of `[-231, 231 - 1]`.

Note: You are not allowed to use any built-in function which evaluates strings
as mathematical expressions, such as `eval()`.


Python solution:
import math
import itertools
import bisect
import collections
import string
import heapq
import functools
import sortedcontainers
from typing import List, Dict, Tuple, Iterator

class Solution:
  def calculate(self, s: str) -> int:
    ans = 0
    prevNum = 0
    currNum = 0
    op = '+'

    for i, c in enumerate(s):
      if c.isdigit():
        currNum = currNum * 10 + int(c)
      if not c.isdigit() and c != ' ' or i == len(s) - 1:
        if op == '+' or op == '-':
          ans += prevNum
          prevNum = currNum if op == '+' else -currNum
        elif op == '*':
          prevNum = prevNum * currNum
        elif op == '/':
          if prevNum < 0:
            prevNum = math.ceil(prevNum / currNum)
          else:
            prevNum = prevNum // currNum
        op = c
        currNum = 0

    return ans + prevNum


Java solution:
class Solution {
  public int calculate(String s) {
    Deque<Integer> nums = new ArrayDeque<>();
    Deque<Character> ops = new ArrayDeque<>();

    for (int i = 0; i < s.length(); ++i) {
      final char c = s.charAt(i);
      if (Character.isDigit(c)) {
        int num = c - '0';
        while (i + 1 < s.length() && Character.isDigit(s.charAt(i + 1))) {
          num = num * 10 + (s.charAt(i + 1) - '0');
          ++i;
        }
        nums.push(num);
      } else if (c == '+' || c == '-' || c == '*' || c == '/') {
        while (!ops.isEmpty() && compare(ops.peek(), c))
          nums.push(calculate(ops.pop(), nums.pop(), nums.pop()));
        ops.push(c);
      }
    }

    while (!ops.isEmpty())
      nums.push(calculate(ops.pop(), nums.pop(), nums.pop()));

    return nums.peek();
  }

  private int calculate(char op, int b, int a) {
    switch (op) {
      case '+':
        return a + b;
      case '-':
        return a - b;
      case '*':
        return a * b;
      case '/':
        return a / b;
    }
    throw new IllegalArgumentException();
  }

  // Returns true if priority(op1) >= priority(op2).
  private boolean compare(char op1, char op2) {
    return op1 == '*' || op1 == '/' || op2 == '+' || op2 == '-';
  }
}


C++ solution:
class Solution {
 public:
  int calculate(string s) {
    stack<int> nums;
    stack<char> ops;

    for (int i = 0; i < s.length(); ++i) {
      const char c = s[i];
      if (isdigit(c)) {
        int num = c - '0';
        while (i + 1 < s.length() && isdigit(s[i + 1])) {
          num = num * 10 + (s[i + 1] - '0');
          ++i;
        }
        nums.push(num);
      } else if (c == '+' || c == '-' || c == '*' || c == '/') {
        while (!ops.empty() && compare(ops.top(), c))
          nums.push(calculate(pop(ops), pop(nums), pop(nums)));
        ops.push(c);
      }
    }

    while (!ops.empty())
      nums.push(calculate(pop(ops), pop(nums), pop(nums)));

    return nums.top();
  }

 private:
  int calculate(char op, int b, int a) {
    switch (op) {
      case '+':
        return a + b;
      case '-':
        return a - b;
      case '*':
        return a * b;
      case '/':
        return a / b;
    }
    throw;
  }

  // Returns true if priority(op1) >= priority(op2).
  bool compare(char op1, char op2) {
    return op1 == '*' || op1 == '/' || op2 == '+' || op2 == '-';
  }

  char pop(stack<char>& ops) {
    const char op = ops.top();
    ops.pop();
    return op;
  }

  int pop(stack<int>& nums) {
    const int num = nums.top();
    nums.pop();
    return num;
  }
};