Post

Expression Evaluation

Fundamentals

InfixPrefix (RN)Postfix (RPN)
a + b+ a ba b +
a + b * c+ a * b ca b c * +
(a + b) * c* + a b ca b + c *
  stack
  • PN: Polish Notation
  • RPN: Reverse Polish Notation

Expression Tree

Build Binary Expression Tree From Infix Expression

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public Node expTree(String s) {
    // converts infix to postfix
    StringBuilder postfix = new StringBuilder();
    Deque<Character> opstack = new ArrayDeque<>();
    for (char c : s.toCharArray()) {
        if (Character.isDigit(c)) {
            postfix.append(c);
        } else {
            if (c == '(') {
                opstack.push(c);
            } else if (c == ')') {
                while (opstack.peek() != '(') {
                    postfix.append(opstack.pop());
                }
                opstack.pop();
            } else if (c == '+' || c == '-') {
                while (!opstack.isEmpty() && opstack.peek() != '(') {
                    postfix.append(opstack.pop());
                }
                opstack.push(c);
            } else {
                while (!opstack.isEmpty() && (opstack.peek() == '*' || opstack.peek() == '/')) {
                    postfix.append(opstack.pop());
                }
                opstack.push(c);
            }
        }
    }

    while (!opstack.isEmpty()) {
        postfix.append(opstack.pop());
    }

    // builds inorder expression tree from postfix
    Deque<Node> operandStack = new ArrayDeque<>();
    for (char c : postfix.toString().toCharArray()) {
        if (Character.isDigit(c)) {
            operandStack.push(new Node(c));
        } else {
            Node right = operandStack.pop(), left = operandStack.pop();
            operandStack.push(new Node(c, left, right)); 
        }
    }
    return operandStack.pop();
}

Basic Calculator III

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
private static final Map<Character, Integer> PRECEDENCE = new HashMap<>();

static {
    PRECEDENCE.put('(', -1);
    PRECEDENCE.put('+', 0);
    PRECEDENCE.put('-', 0);
    PRECEDENCE.put('*', 1);
    PRECEDENCE.put('/', 1);
}

public int calculate(String s) {
    // infix -> postfix
    Deque<Integer> operands = new ArrayDeque<>();
    Deque<Character> operators = new ArrayDeque<>();
    int n = s.length();
    for (int i = 0; i < n; i++) {
        char c = s.charAt(i);
        if (Character.isDigit(c)) {
            int val = Character.getNumericValue(s.charAt(i));
            while (i + 1 < n && Character.isDigit(s.charAt(i + 1))) {
                val = val * 10 + Character.getNumericValue(s.charAt(i + 1));
                i++;
            }
            operands.push(val);
        } else if (c == '(') {
            operators.push(c);
        } else if (c == ')') {
            while (operators.peek() != '(') {
                operands.push(operate(operands, operators));
            }
            operators.pop();
        } else {
            while (!operators.isEmpty() && compare(c, operators.peek()) <= 0) {
                operands.push(operate(operands, operators));
            }
            operators.push(c);
        }
    }

    while (!operators.isEmpty()) {
        operands.push(operate(operands, operators));
    }

    return operands.pop();
}

// precedence
private int compare(char a, char b) {
    return PRECEDENCE.get(a) - PRECEDENCE.get(b);
}

private int operate(Deque<Integer> operands, Deque<Character> operators) {
    int a = operands.pop(), b = operands.pop();
    char c = operators.pop();

    switch (c) {
        case '+' : return a + b;
        case '-': return b - a;
        case '*': return a * b;
        case '/': return b / a;
        default: return 0;
    }
}

Dynamic Programming

The Score of Students Solving Math Expression

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
private static final int MAX_ANSWER = 1000;

public int scoreOfStudents(String s, int[] answers) {
    // number of digits
    int n = s.length() / 2 + 1;
    // dp[i][j]: set of possible results of s[i...j], where the index is of digits only
    // e.g. 1 + 2 * 3, index 2 stands for 3
    Set<Integer>[][] dp = new Set[n][n];
    for (int i = 0; i < n; i++) {
        dp[i][i] = new HashSet<>();
        // 2 * i is the actual index of the digit in the stringg
        dp[i][i].add(s.charAt(2 * i) - '0');
    }

    for (int len = 1; len < n; len++) {
        for (int i = 0; i + len < n; i++) {
            int j = i + len;
            dp[i][j] = new HashSet<>();
            // index of operators
            for (int k = 2 * i + 1; k < 2 * j; k += 2) {
                for (int a : dp[i][k / 2]) {
                    for (int b : dp[k / 2 + 1][j]) {
                        if (s.charAt(k) == '+' && a + b <= MAX_ANSWER) {
                            dp[i][j].add(a + b);
                        } else if (s.charAt(k) == '*' && a * b <= MAX_ANSWER) {
                            dp[i][j].add(a * b);
                        }

                    }
                }
            }
        }
    }

    int val = evaluate(s), points = 0;
    for (int a : answers) {
        if (a == val) {
            points += 5;
        } else if (dp[0][n - 1].contains(a)) {
            points += 2;
        }
    }
    return points;
}

// evaluate
private int evaluate(String s) {
    Deque<Integer> st = new ArrayDeque<>();
    char operator = '+';
    int i = 0, num = 0;
    while (i < s.length()) {
        char ch = s.charAt(i++);
        if (Character.isDigit(ch)) {
            num = ch - '0';
        }
        if (i >= s.length() || ch == '+' || ch == '*') {
            if (operator == '+') {
                st.push(num);
            } else if (operator == '*') {
                st.push(st.pop() * num);
            }
            operator = ch;
        }
    }
    return st.stream().mapToInt(Integer::intValue).sum();
}
This post is licensed under CC BY 4.0 by the author.