-
Notifications
You must be signed in to change notification settings - Fork 44
/
Copy pathbuild-binary-expression-tree-from-infix-expression.py
273 lines (224 loc) · 9.3 KB
/
build-binary-expression-tree-from-infix-expression.py
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
"""
1597. Build Binary Expression Tree From Infix Expression
Hard
A binary expression tree is a kind of binary tree used to represent arithmetic expressions. Each node of a binary expression tree has either zero or two children. Leaf nodes (nodes with 0 children) correspond to operands (numbers), and internal nodes (nodes with 2 children) correspond to the operators '+' (addition), '-' (subtraction), '*' (multiplication), and '/' (division).
For each internal node with operator o, the infix expression that it represents is (A o B), where A is the expression the left subtree represents and B is the expression the right subtree represents.
You are given a string s, an infix expression containing operands, the operators described above, and parentheses '(' and ')'.
Return any valid binary expression tree, which its in-order traversal reproduces s after omitting the parenthesis from it (see examples below).
Please note that order of operations applies in s. That is, expressions in parentheses are evaluated first, and multiplication and division happen before addition and subtraction.
Operands must also appear in the same order in both s and the in-order traversal of the tree.
Example 1:
Input: s = "3*4-2*5"
Output: [-,*,*,3,4,2,5]
Explanation: The tree above is the only valid tree whose inorder traversal produces s.
Example 2:
Input: s = "2-3/(5*2)+1"
Output: [+,-,1,2,/,null,null,null,null,3,*,null,null,5,2]
Explanation: The inorder traversal of the tree above is 2-3/5*2+1 which is the same as s without the parenthesis. The tree also produces the correct result and its operands are in the same order as they appear in s.
The tree below is also a valid binary expression tree with the same inorder traversal as s, but it not a valid answer because it does not evaluate to the same value.
The third tree below is also not valid. Although it produces the same result and is equivalent to the above trees, its inorder traversal does not produce s and its operands are not in the same order as s.
Example 3:
Input: s = "1+2+3+4+5"
Output: [+,+,5,+,4,null,null,+,3,null,null,1,2]
Explanation: The tree [+,+,5,+,+,null,null,1,2,3,4] is also one of many other valid trees.
Constraints:
1 <= s.length <= 1000
s consists of digits and the characters '+', '-', '*', and '/'.
Operands in s are exactly 1 digit.
It is guaranteed that s is a valid expression.
"""
# V0
# IDEA : LC 224 Basic Calculator
class Solution(object):
def help(self, numSt, opSt):
right = numSt.pop()
left = numSt.pop()
# Node(val=op, left=lhs, right=rhs)
return Node(opSt.pop(), left, right)
def expTree(self, s):
# hashmap for operator ordering
pr = {'*': 1, '/': 1, '+': 2, '-': 2, ')': 3, '(': 4}
numSt = []
opSt = []
i = 0
while i < len(s):
c = s[i]
i += 1
# check if int(c) if string
if c.isnumeric():
numSt.append(Node(c))
else:
if c == '(':
opSt.append('(')
else:
while(len(opSt) > 0 and pr[c] >= pr[opSt[-1]]):
numSt.append(self.help(numSt, opSt))
if c == ')':
opSt.pop() # Now what remains is the closing bracket ')'
else:
opSt.append(c)
while len(opSt) > 0:
numSt.append(self.help(numSt, opSt))
print (">>> numSt = {}, opSt = {}".format(str(numSt), opSt))
return numSt.pop()
# V0'
# IDEA : RECURSIVE
class Solution:
def expTree(self, s):
n = len(s)
if n == 1:
return Node(s)
fstOpIdx = None
kets = 0
for i in range(n-1, 0, -1):
if s[i] == ")":
kets += 1
elif s[i] == "(":
kets -= 1
elif kets == 0:
if s[i] in "+-":
fstOpIdx = i
break
elif s[i] in "*/" and fstOpIdx is None:
fstOpIdx = i
if fstOpIdx is None:
return self.expTree(s[1:-1])
rtNd = Node(s[fstOpIdx])
rtNd.left = self.expTree(s[:fstOpIdx])
rtNd.right = self.expTree(s[fstOpIdx+1:])
return rtNd
# V1
# https://leetcode.com/problems/build-binary-expression-tree-from-infix-expression/discuss/864596/Python-Standard-parser-implementation
class Solution:
# Standard parser implementation based on this BNF
# s := expression
# expression := term | term { [+,-] term] }
# term := factor | factor { [*,/] factor] }
# factor :== digit | '(' expression ')'
# digit := [0..9]
def expTree(self, s):
tokens = collections.deque(list(s))
return self.parse_expression(tokens)
def parse_expression(self, tokens):
lhs = self.parse_term(tokens)
while len(tokens) > 0 and tokens[0] in ['+', '-']:
op = tokens.popleft()
rhs = self.parse_term(tokens)
lhs = Node(val=op, left=lhs, right=rhs)
return lhs
def parse_term(self, tokens):
lhs = self.parse_factor(tokens)
while len(tokens) > 0 and tokens[0] in ['*', '/']:
op = tokens.popleft()
rhs = self.parse_factor(tokens)
lhs = Node(val=op, left=lhs, right=rhs)
return lhs
def parse_factor(self, tokens):
if tokens[0] == '(':
tokens.popleft() # consume '('
node = self.parse_expression(tokens)
tokens.popleft() # consume ')'
return node
else:
# Single operand
token = tokens.popleft()
return Node(val=token)
# V1'
# IDEA : LC 224 Basic Calculator
# https://leetcode.com/problems/build-binary-expression-tree-from-infix-expression/discuss/944215/Python-Solution-Similar-to-Basic-Calculator
class Solution(object):
def apply(self, numSt, opSt):
right = numSt.pop()
left = numSt.pop()
return Node(opSt.pop(), left, right)
def expTree(self, s):
pr = {'*': 1, '/': 1, '+': 2, '-': 2, ')': 3, '(': 4}
numSt, opSt = [], []
i = 0
while (i < len(s)):
c = s[i]
i += 1
if c.isnumeric():
numSt.append(Node(c))
else:
if c in '(':
opSt.append('(')
else:
while(len(opSt) > 0 and pr[c] >= pr[opSt[-1]]):
numSt.append(self.apply(numSt, opSt))
if (c == ')'):
opSt.pop() # Now what remains is the closing bracket ')'
else:
opSt.append(c)
while len(opSt) > 0:
numSt.append(self.apply(numSt, opSt))
return numSt.pop()
# V1''
# IDEA : RECURSIVE
# https://leetcode.com/problems/build-binary-expression-tree-from-infix-expression/discuss/985360/Python-3-recursion-and-easy-to-understand
class Solution:
def expTree(self, s):
n = len(s)
if n == 1:
return Node(s)
fstOpIdx = None
kets = 0
for i in range(n-1, 0, -1):
if s[i] == ")":
kets += 1
elif s[i] == "(":
kets -= 1
elif kets == 0:
if s[i] in "+-":
fstOpIdx = i
break
elif s[i] in "*/" and fstOpIdx is None:
fstOpIdx = i
if fstOpIdx is None:
return self.expTree(s[1:-1])
rtNd = Node(s[fstOpIdx])
rtNd.left = self.expTree(s[:fstOpIdx])
rtNd.right = self.expTree(s[fstOpIdx+1:])
return rtNd
# V1'''
# https://leetcode.com/problems/build-binary-expression-tree-from-infix-expression/discuss/862421/Python-O(n)-single-pass-Handles-multiple-digits-and-negative-numbers
class Solution:
def expTree(self, expression: str) -> 'Node':
precedence = {'/':2, '*':2, '+':1, '-':1}
ops = {'/','*','+','-'}
operator = []
operand = [Node('0')]
i = 0
while i<len(expression):
ch = expression[i]
if ch.isdigit():
start = i
while i<len(expression) and expression[i].isdigit():
i += 1
num = expression[start:i]
operand.append(Node(num))
i -= 1
elif ch in ops:
while len(operator) and operator[-1].val!='(' and precedence[operator[-1].val] >= precedence[ch]:
self.process(operator, operand)
operator.append(Node(ch))
elif ch == '(':
operator.append(Node(ch));
if expression[i+1] == '-':
operand.append(Node('0'))
elif ch == ')':
while operator[-1].val != '(':
self.process(operator, operand)
operator.pop()
i += 1
while len(operator):
self.process(operator,operand)
return operand.pop()
def process(self,operator_stack, operand_stack):
node2 = operand_stack.pop()
node1 = operand_stack.pop()
node = operator_stack.pop()
node.left = node1
node.right = node2
operand_stack.append(node)
# V2