package com.freetymekiyan.algorithms.level.medium;

/**
 * Implement a basic calculator to evaluate a simple expression string.
 * <p>
 * The expression string contains only non-negative integers, +, -, *, / operators and empty spaces . The integer
 * division should truncate toward zero.
 * <p>
 * You may assume that the given expression is always valid.
 * <p>
 * Some examples:
 * "3+2*2" = 7
 * " 3/2 " = 1
 * " 3+5 / 2 " = 5
 * Note: Do not use the eval built-in library function.
 * <p>
 * Tags: String
 * Similar Problems: (H) Basic Calculator, (H) Expression Add Operators
 */
public class BasicCalculator2 {

    /**
     * The easy way would be using a stack to store high priority results and integers.
     * Then go through the stack to get final result.
     * How to remove the stack? How to do it in only one-pass?
     * We have only two priority levels, '*' '/' and '+' '-'.
     * They can separated into two results, high level value and low level value.
     * https://discuss.leetcode.com/topic/42684/explanation-for-java-o-n-time-o-1-space-solution
     */
    public int calculate(String s) {
        int lowVal = 0; // Result for low level operators like '+' and '-'
        int highVal = 0; // Result for high level operators like '*' and '/'
        int sign = 1; // 1 means '+', -1 means '-'
        int priority = 0; // 0 means '+' and '-', 1 means '*', -1 means '/'
        int num = 0; // Current number

        for (int i = 0; i < s.length(); i++) {
            char c = s.charAt(i);
            if (Character.isDigit(c)) {
                num = num * 10 + (c - '0');
                if (i == s.length() - 1 || !Character.isDigit(s.charAt(i + 1))) {
                    highVal = (priority == 0 ? num : (priority == 1 ? highVal * num : highVal / num));
                }
            } else if (c == '*' || c == '/') { // Enter high level
                priority = (c == '*' ? 1 : -1); // Update priority
                num = 0; // Reset current number
            } else if (c == '+' || c == '-') { // Enter low level
                lowVal += sign * highVal; // Accumulate high level result to low level
                sign = (c == '+' ? 1 : -1); // Update sign
                priority = 0; // Update priority
                num = 0; // Reset current number
            }
        }

        return lowVal + sign * highVal;
    }

}

add Basic Calculator 2