LeetCode Solutions

772. Basic Calculator III

Time: $O(n)$

Space: $O(n)$

			

class Solution {
 public:
  int calculate(string s) {
    stack<int> nums;
    stack<int> ops;
    bool hasPrevNum = false;

    auto calc = [&]() {
      const int b = nums.top();
      nums.pop();
      const int a = nums.top();
      nums.pop();
      const char op = ops.top();
      ops.pop();
      if (op == '+')
        nums.push(a + b);
      else if (op == '-')
        nums.push(a - b);
      else if (op == '*')
        nums.push(a * b);
      else  // Op == '/'
        nums.push(a / b);
    };

    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');
        nums.push(num);
        hasPrevNum = true;
      } else if (c == '(') {
        ops.push('(');
        hasPrevNum = false;
      } else if (c == ')') {
        while (ops.top() != '(')
          calc();
        ops.pop();  // Pop '('
      } else if (c == '+' || c == '-' || c == '*' || c == '/') {
        if (!hasPrevNum)
          nums.push(0);
        while (!ops.empty() && precedes(ops.top(), c))
          calc();
        ops.push(c);
      }
    }

    while (!ops.empty())
      calc();

    return nums.top();
  }

 private:
  // Returns true if prevOp is a operator and
  // Priority(prevOp) >= priority(currOp)
  bool precedes(char prevOp, char currOp) {
    if (prevOp == '(')
      return false;
    return prevOp == '*' || prevOp == '/' || currOp == '+' || currOp == '-';
  }
};
			

class Solution {
  public int calculate(String s) {
    Deque<Integer> nums = new ArrayDeque<>();
    Deque<Character> ops = new ArrayDeque<>();
    boolean hasPrevNum = false;

    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');
        nums.push(num);
        hasPrevNum = true;
      } else if (c == '(') {
        ops.push('(');
        hasPrevNum = false;
      } else if (c == ')') {
        while (ops.peek() != '(')
          calc(nums, ops);
        ops.pop(); // Pop '('
      } else if (c == '+' || c == '-' || c == '*' || c == '/') {
        if (!hasPrevNum)
          nums.push(0);
        while (!ops.isEmpty() && precedes(ops.peek(), c))
          calc(nums, ops);
        ops.push(c);
      }
    }

    while (!ops.isEmpty())
      calc(nums, ops);

    return nums.peek();
  }

  private void calc(Deque<Integer> nums, Deque<Character> ops) {
    final int b = nums.pop();
    final int a = nums.pop();
    final 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 // Op == '/'
      nums.push(a / b);
  }

  // Returns true if prevOp is a operator and
  // Priority(prevOp) >= priority(currOp)
  private boolean precedes(char prevOp, char currOp) {
    if (prevOp == '(')
      return false;
    return prevOp == '*' || prevOp == '/' || currOp == '+' || currOp == '-';
  }
}
			

class Solution:
  def calculate(self, s: str) -> int:
    nums = []
    ops = []

    def calc():
      b = nums.pop()
      a = nums.pop()
      op = ops.pop()
      if op == '+':
        nums.append(a + b)
      elif op == '-':
        nums.append(a - b)
      elif op == '*':
        nums.append(a * b)
      else:  # Op == '/'
        nums.append(int(a / b))

    # Returns true if prevOp is a operator and
    # Priority(prevOp) >= priority(currOp)
    def precedes(prevOp: chr, currOp: chr) -> bool:
      if prevOp == '(':
        return False
      return prevOp in '*/' or currOp in '+-'

    i = 0
    hasPrevNum = False

    while i < len(s):
      c = s[i]
      if c.isdigit():
        num = ord(c) - ord('0')
        while i + 1 < len(s) and s[i + 1].isdigit():
          num = num * 10 + (ord(s[i + 1]) - ord('0'))
          i += 1
        nums.append(num)
        hasPrevNum = True
      elif c == '(':
        ops.append('(')
        hasPrevNum = False
      elif c == ')':
        while ops[-1] != '(':
          calc()
        ops.pop()  # Pop '('
      elif c in '+-*/':
        if not hasPrevNum:  # Handle input like "-1-(-1)"
          num.append(0)
        while ops and precedes(ops[-1], c):
          calc()
        ops.append(c)
      i += 1

    while ops:
      calc()

    return nums.pop()