This repository was archived by the owner on Sep 20, 2023. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 164
/
Copy pathbasic-calculator-iv.go
executable file
·218 lines (189 loc) · 4.17 KB
/
basic-calculator-iv.go
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
package problem0770
import (
"sort"
"strconv"
"strings"
)
func basicCalculatorIV(expression string, evalvars []string, evalints []int) []string {
// 把 evalvars 和 evalints 转换成 eemap
eemap := make(map[string]int, len(evalvars))
for i := range evalvars {
eemap[evalvars[i]] = evalints[i]
}
// 删除 expression 中的所有空格,为下面的 parse 有准备
expression = strings.Replace(expression, " ", "", -1)
numbers := parse(expression, eemap)
return format(numbers)
}
func parse(expression string, m map[string]int) nums {
// n1 opt1 n2 opt2 n3 opt3 ...
// 根据 opt2 是否为 * 决定运算顺序
// 像以下这样提前设置 n1,n2,opt1,opt2
// 不会改变运算结果,却可以简化 for 循环
n1, n2 := nums{num{c: 0}}, nums{num{c: 0}}
opt1, opt2 := byte('+'), byte('+')
for {
var n3 nums
var i int
// 获取 n3
if expression[0] == '(' {
// 遇见括号,就把括号中的内容取出,进行递归
i = indexOfCounterParentheses(expression)
n3 = parse(expression[1:i], m)
// i++前,i 是右括号的索引值
i++
// i++后,i 是右括号右边的运算符号的索引值
} else {
i = indexOfNextOpt(expression)
n3 = creatNums(expression[:i], m)
}
// 根据 opt2 进行不同的运算
if opt2 == '*' {
n2 = operate(opt2, n2, n3)
} else {
n1 = operate(opt1, n1, n2)
n2 = n3
opt1 = opt2
}
// 检查 i ,确保后续操作不溢出
if i == len(expression) {
break
}
opt2 = expression[i]
expression = expression[i+1:]
}
return operate(opt1, n1, n2)
}
func creatNums(exp string, m map[string]int) nums {
constant, ok := m[exp]
if ok {
return nums{num{c: constant}}
}
constant, err := strconv.Atoi(exp)
if err != nil {
return nums{num{vars: []string{exp}, c: 1}}
}
return nums{num{c: constant}}
}
func operate(opt byte, a, b nums) nums {
var res nums
switch opt {
case '+':
res = add(a, b)
case '-':
res = minus(a, b)
case '*':
res = mult(a, b)
}
return res
}
func add(a, b nums) nums {
return append(a, b...)
}
func minus(a, b nums) nums {
for i := range b {
b[i].c *= -1
}
return append(a, b...)
}
func mult(a, b nums) nums {
res := make(nums, 0, len(a)*len(b))
for i := range a {
for j := range b {
vars := make([]string, 0, len(a[i].vars)+len(b[j].vars))
vars = append(vars, a[i].vars...)
vars = append(vars, b[j].vars...)
res = append(res, num{vars: vars, c: a[i].c * b[j].c})
}
}
return res
}
func indexOfCounterParentheses(expression string) int {
i := 1
count := 1
for ; i < len(expression); i++ {
switch expression[i] {
case '(':
count++
case ')':
count--
}
if count == 0 {
break
}
}
return i
}
func indexOfNextOpt(expression string) int {
var i int
for i = 1; i < len(expression); i++ {
if expression[i] == '+' ||
expression[i] == '-' ||
expression[i] == '*' {
break
}
}
return i
}
func format(numbers nums) []string {
numbers = update(numbers)
res := make([]string, 0, len(numbers))
for _, n := range numbers {
if n.c == 0 {
continue
}
temp := strconv.Itoa(n.c)
if n.key != "" {
temp = temp + "*" + n.key
}
res = append(res, temp)
}
return res
}
type nums []num
type num struct {
vars []string // 变量
key string // vars 排序后,使用 "*" 连接,成为 key
c int // 系数
}
func update(ns nums) nums {
// 更新每个 num 的 key
for i := range ns {
sort.Strings(ns[i].vars)
ns[i].key = strings.Join(ns[i].vars, "*")
}
// 对 ns 进行排序
sort.Slice(ns, func(i int, j int) bool {
leni := len(ns[i].vars)
lenj := len(ns[j].vars)
// 首先,变量多的放在前面
if leni != lenj {
return leni > lenj
}
// 变量一样多的时候
// 不同变量,小的放在前面
for k := 0; k < leni; k++ {
if ns[i].vars[k] == ns[j].vars[k] {
continue
}
return ns[i].vars[k] < ns[j].vars[k]
}
// i,j 所有变量都一样的时候
// 返回 false 表示不用交换
return false
})
// 合并相同 key 的 c
res := make(nums, 1, len(ns))
res[0] = ns[0]
i, j := 0, 1
for j < len(ns) {
if res[i].key == ns[j].key {
res[i].c += ns[j].c
} else {
res = append(res, ns[j])
i++
}
j++
}
return res
}