Saturday, March 2, 2019

Leetcode 772. Basic Calculator III

Implement a basic calculator to evaluate a simple expression string.
The expression string may contain open ( and closing parentheses ), the plus + or minus sign -non-negative integers and empty spaces .
The expression string contains only non-negative integers, +-*/ operators , open ( and closing parentheses ) and empty spaces . 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 [-2147483648, 2147483647].
Some examples:
"1 + 1" = 2
" 6-4 / 2 " = 4
"2*(5+5*2)/3+(6/2+8)" = 21
"(2+6* 3+5- (3*14/7+2)*5)+3"=-12

Note: Do not use the eval built-in library function.

Code (Java):
class Solution {
    public int calculate(String s) {
        if (s == null || s.length() == 0) {
            return 0;
        }

        // remove leading and trailing spaces and white spaces.
        //
        s = s.trim().replaceAll("[ ]+", "");

        if (s == null || s.length() == 0) {
            return 0;
        }

        Stack<Character> opStack = new Stack<>();
        Stack<Integer> numStack = new Stack<>();

        int i = 0;
        while (i < s.length()) {
            if (Character.isDigit(s.charAt(i))) {
                int num = 0;
                while (i < s.length() && Character.isDigit(s.charAt(i))) {
                    num = num * 10 + Character.getNumericValue(s.charAt(i));
                    i++;
                }
                numStack.push(num);
            } else {
                char op = s.charAt(i);
                if (opStack.isEmpty()) {
                    opStack.push(op);
                    i++;
                } else if (op == '+' || op == '-') {
                    char top = opStack.peek();
                    if (top == '(') {
                        opStack.push(op);
                        i++;
                    } else {
                        calculate(numStack, opStack);
                    }
                } else if (op == '*' || op == '/') {
                    char top = opStack.peek();
                    if (top == '(') {
                        opStack.push(op);
                        i++;
                    } else if (top == '*' || top == '/') {
                        calculate(numStack, opStack);
                    } else if (top == '+' || top == '-') {
                        opStack.push(op);
                        i++;
                    }
                } else if (op == '(') {
                    opStack.push(op);
                    i++;
                } else if (op == ')') {
                    while (opStack.peek() != '(') {
                        calculate(numStack, opStack);
                    }
                    opStack.pop();
                    i++;
                }
            }
        }

        while (!opStack.isEmpty()) {
            calculate(numStack, opStack);
        }

        return numStack.peek();
    }
    
    private void calculate(Stack<Integer> numStack, Stack<Character> opStack) {
        int num2 = numStack.pop();
        int num1 = numStack.pop();
        
        char op = opStack.pop();
        
        int ans = 0;
        
        switch(op) {
            case '+':
                ans = num1 + num2;
            break;
            case '-':
                ans = num1 - num2;
            break;
            case '*':
                ans = num1 * num2;
            break;
            case '/':
                ans = num1 / num2;
            break;
        }
        
        numStack.push(ans);
    }
}

3 comments:

  1. This is a very nicely thought out code. Takes care of all needed details in great and succinct way. For example, when popping the stack in 'calculate' method, the assignment of the first popped number to num2 (not num1) variable, solves the problem of potentially incorrect subtraction handling so simply. A very nice way of making multiplication/division precedence over addition/subtraction in parentheses are not enforcing this precedence. Summarizing - a very nice job!

    ReplyDelete
  2. So intuitive and good solution. Thanks a ton dude!

    ReplyDelete
  3. This breaks for a simple expression: "-2+1"
    Please fix it up.

    ReplyDelete