/
Basic Calculator.java
executable file
·154 lines (136 loc) · 4.67 KB
/
Basic Calculator.java
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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
H
1526882596
tags: Stack, Math, Expression Tree, Binary Tree, Minimum Binary Tree
给一个expression String, 要evaluate这个expression的值.
Expression string 里面包括 +, -, 整数, 开合括号, 还有space.
#### Expression Tree
- Expression Tree是一个 weight-based的 min-tree
- 基于 运算符号 + 数字的 tree: 数字永远在leaf, 然后符号是tree node, 括号不出现在tree里面
- 用 monotonuous stack 来构建这个tree
##### Thinking points
- Understand Expression Tree
- Use stack to build the expression tree + understand the weight system
- Use post-order traversal to evaluate the tree
- 注意, input里面的数字不会是single digit, 所以需要一个buffer存number string
- 整个题目的做法, 可以参照 `Expression Evaluation`
```
/*
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 .
You may assume that the given expression is always valid.
Some examples:
"1 + 1" = 2
" 2-1 + 2 " = 3
"(1+(4+5+2)-3)+(6+8)" = 23
Note: Do not use the eval built-in library function.
*/
/*
build expression tree to evaluate expression
two functions:
1. build tree
parse string
skip space
identify operator
calculate weight of operator
add parentheses to base weight
2. evaluate with post-order traversal
*/
class Solution {
class TreeNode {
int weight;
String str;
TreeNode left, right;
public TreeNode(int weight, String str) {
this.weight = weight;
this.str = str;
}
}
public int calculate(String s) {
if (s == null || s.length() == 0) return 0;
TreeNode root = buildTree(s); // build expression tree
return (int)evaluate(root); // post-order traversal of the tree
}
// build tree based on input string, min-tree. return root
private TreeNode buildTree(String s) {
int n = s.length();
char[] chars = s.trim().toCharArray();
Stack<TreeNode> stack = new Stack<>();
int base = 0;
StringBuffer sb = new StringBuffer();
for (int i = 0; i < n; i++) {
char c = chars[i];
if (c == ' ') {
continue;
} else if (c == '(') { // '()' are used to add weight, not stored in tree
base = getWeight(base, c);
continue;
} else if (c == ')') {
base = getWeight(base, c);
continue;
} else if (i < n - 1 && isDigit(chars[i]) && isDigit(chars[i + 1])) { // continue to get remaining of the int
sb.append(c);
continue;
}
String str;
if (isDigit(c)) {
sb.append(c);
str = sb.toString();
sb.setLength(0); // clean up
} else {
str = c + "";
}
// use monotonuous stack to build min-tree
TreeNode node = new TreeNode(getWeight(base, c), str);
while (!stack.isEmpty() && node.weight <= stack.peek().weight) {
node.left = stack.pop();
}
if (!stack.isEmpty()) {
stack.peek().right = node;
}
stack.push(node);
}
TreeNode root = null;
while (!stack.isEmpty()) {
root = stack.pop();
}
return root; // it's the root of tree, always a operator
}
// post-order traversal to evaluate the expression
private long evaluate(TreeNode root) {
if (root == null) return 0;
long left = evaluate(root.left);
long right = evaluate(root.right);
long result = 0;
switch(root.str) {
case "+":
result = left + right;
break;
case "-":
result = left - right;
break;
case "*":
result = left * right;
break;
case "/":
result = left / right;
break;
default:
result = Long.parseLong(root.str);
}
return result;
}
// get weight of the character. integer weights the most and will be leaf.
// Remember to store the result using long
private int getWeight(int base, char c) {
if (c == '(') return base + 10;
if (c == ')') return base - 10;
if (c == '+' || c == '-') return base + 1;
if (c == '*' || c == '/') return base + 2;
return Integer.MAX_VALUE;
}
private boolean isDigit(char c) {
return c >= '0' && c <= '9';
}
}
```