Skip to content

Commit d40e5e2

Browse files
authored
Improved task 770.
1 parent 011e8a5 commit d40e5e2

File tree

2 files changed

+160
-117
lines changed

2 files changed

+160
-117
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,158 +1,193 @@
11
package g0701_0800.s0770_basic_calculator_iv;
22

33
// #Hard #String #Hash_Table #Math #Stack #Recursion
4-
// #2022_03_26_Time_17_ms_(66.18%)_Space_45.8_MB_(60.29%)
4+
// #2022_04_30_Time_8_ms_(96.92%)_Space_42.9_MB_(93.85%)
55

66
import java.util.ArrayList;
77
import java.util.Collections;
88
import java.util.HashMap;
9-
import java.util.LinkedList;
109
import java.util.List;
1110
import java.util.Map;
1211

13-
@SuppressWarnings("java:S1104")
1412
public class Solution {
15-
public List<String> basicCalculatorIV(String expression, String[] evalvars, int[] evalints) {
16-
Map<String, Integer> knownVars = new HashMap<>();
17-
for (int i = 0; i < evalvars.length; i++) {
18-
knownVars.put(evalvars[i], evalints[i]);
19-
}
20-
LinkedList<Expr> expressions = new LinkedList<>();
21-
LinkedList<String> ops = new LinkedList<>();
22-
for (String token : parseExpression(expression)) {
23-
if (Character.isDigit(token.charAt(0))) {
24-
expressions.push(new Expr("", Integer.parseInt(token)));
25-
} else if (token.equals("(")) {
26-
ops.push("(");
27-
} else if (token.equals(")")) {
28-
while (!ops.peek().equals("(")) {
29-
doOneEval(ops, expressions);
13+
private static class Result {
14+
private Map<List<String>, Integer> map;
15+
16+
Result() {
17+
map = new HashMap<>();
18+
}
19+
20+
Result(Map<List<String>, Integer> map) {
21+
this.map = map;
22+
}
23+
24+
void update(List<String> key, int val) {
25+
map.put(key, map.getOrDefault(key, 0) + val);
26+
}
27+
28+
Map<List<String>, Integer> getMap() {
29+
return map;
30+
}
31+
32+
List<String> toList() {
33+
List<List<String>> keyList = new ArrayList<>(map.keySet());
34+
Map<List<String>, String> list2String = new HashMap<>();
35+
for (List<String> key : keyList) {
36+
StringBuilder sb = new StringBuilder();
37+
for (String k : key) {
38+
sb.append(k).append("*");
3039
}
31-
ops.pop();
32-
} else if (token.equals("+") || token.equals("-") || token.equals("*")) {
33-
int rank = getRank(token);
34-
while (!ops.isEmpty() && !ops.peek().equals("(") && getRank(ops.peek()) >= rank) {
35-
doOneEval(ops, expressions);
40+
list2String.put(key, sb.toString());
41+
}
42+
keyList.sort(
43+
(a, b) ->
44+
(a.size() == b.size()
45+
? list2String.get(a).compareTo(list2String.get(b))
46+
: b.size() - a.size()));
47+
List<String> res = new ArrayList<>();
48+
for (List<String> key : keyList) {
49+
if (map.get(key) == 0) {
50+
continue;
3651
}
37-
ops.push(token);
38-
} else if (knownVars.containsKey(token)) {
39-
expressions.push(new Expr("", knownVars.get(token)));
40-
} else {
41-
expressions.push(new Expr(token, 1));
52+
StringBuilder sb = new StringBuilder();
53+
sb.append(map.get(key));
54+
for (String k : key) {
55+
sb.append("*").append(k);
56+
}
57+
res.add(sb.toString());
4258
}
59+
return res;
4360
}
44-
while (!ops.isEmpty()) {
45-
doOneEval(ops, expressions);
61+
}
62+
63+
private Map<String, Integer> evalMap;
64+
private int i = 0;
65+
66+
public List<String> basicCalculatorIV(String expression, String[] evalvars, int[] evalints) {
67+
evalMap = new HashMap<>();
68+
for (int j = 0; j < evalvars.length; j++) {
69+
evalMap.put(evalvars[j], evalints[j]);
4670
}
47-
Expr expr = expressions.peek();
48-
List<String> output = new ArrayList<>();
49-
for (String term : expr.terms.keySet()) {
50-
if (expr.terms.get(term) != 0) {
51-
output.add("" + expr.terms.get(term) + (term.equals("") ? "" : "*" + term));
71+
i = -1;
72+
next(expression);
73+
Result res = expression(expression);
74+
return res.toList();
75+
}
76+
77+
private Result expression(String s) {
78+
Result res = term(s);
79+
while (i < s.length() && (s.charAt(i) == '+' || s.charAt(i) == '-')) {
80+
int c = s.charAt(i);
81+
next(s);
82+
if (c == '+') {
83+
res = add(res, term(s));
84+
} else {
85+
res = subtract(res, term(s));
5286
}
5387
}
54-
output.sort(
55-
(a, b) -> {
56-
int aStar = 0;
57-
int bStar = 0;
58-
for (int i = 0; i < a.length(); i++) {
59-
if (a.charAt(i) == '*') {
60-
aStar++;
61-
}
62-
}
63-
for (int i = 0; i < b.length(); i++) {
64-
if (b.charAt(i) == '*') {
65-
bStar++;
66-
}
67-
}
68-
if (aStar != bStar) {
69-
return bStar - aStar;
70-
}
71-
return a.split("\\*", 2)[1].compareTo(b.split("\\*", 2)[1]);
72-
});
73-
return output;
88+
return res;
7489
}
7590

76-
private int getRank(String op) {
77-
if (op.equals("+") || op.equals("-")) {
78-
return 1;
91+
private Result term(String s) {
92+
Result res = factor(s);
93+
while (i < s.length() && s.charAt(i) == '*') {
94+
next(s);
95+
res = multiply(res, factor(s));
7996
}
80-
// *
81-
return 2;
97+
return res;
8298
}
8399

84-
private List<String> parseExpression(String s) {
85-
List<String> output = new ArrayList<>();
86-
for (String token : s.split(" ")) {
87-
int opening = 0;
88-
for (; token.charAt(opening) == '('; opening++) {
89-
output.add("(");
90-
}
91-
int closing = 0;
92-
while (token.charAt(token.length() - 1 - closing) == ')') {
93-
closing++;
94-
}
95-
output.add(token.substring(opening, token.length() - closing));
96-
while (closing-- > 0) {
97-
output.add(")");
100+
private Result multiply(Result r1, Result r2) {
101+
Map<List<String>, Integer> map1 = r1.getMap();
102+
Map<List<String>, Integer> map2 = r2.getMap();
103+
Map<List<String>, Integer> map = new HashMap<>();
104+
for (Map.Entry<List<String>, Integer> entry1 : map1.entrySet()) {
105+
for (Map.Entry<List<String>, Integer> entry2 : map2.entrySet()) {
106+
List<String> key = new ArrayList<>(entry1.getKey());
107+
key.addAll(entry2.getKey());
108+
Collections.sort(key);
109+
map.put(key, map.getOrDefault(key, 0) + entry1.getValue() * entry2.getValue());
98110
}
99111
}
100-
return output;
112+
return new Result(map);
101113
}
102114

103-
private void doOneEval(LinkedList<String> ops, LinkedList<Expr> expressions) {
104-
Expr e2 = expressions.pop();
105-
Expr e1 = expressions.pop();
106-
Expr res = new Expr("", 0);
107-
String op = ops.pop();
108-
if (op.equals("+") || op.equals("-")) {
109-
int sign = op.equals("-") ? -1 : 1;
110-
res.terms = e1.terms;
111-
for (String term : e2.terms.keySet()) {
112-
res.terms.put(term, sign * e2.terms.get(term) + res.terms.getOrDefault(term, 0));
113-
}
114-
} else {
115-
// *
116-
for (String t1 : e1.terms.keySet()) {
117-
for (String t2 : e2.terms.keySet()) {
118-
String resTerm = generateTerm(t1, t2);
119-
res.terms.put(
120-
resTerm,
121-
e1.terms.get(t1) * e2.terms.get(t2)
122-
+ res.terms.getOrDefault(resTerm, 0));
123-
}
124-
}
115+
private Result add(Result r1, Result r2) {
116+
Map<List<String>, Integer> map1 = r1.getMap();
117+
Map<List<String>, Integer> map2 = r2.getMap();
118+
Map<List<String>, Integer> map = new HashMap<>();
119+
for (Map.Entry<List<String>, Integer> entry1 : map1.entrySet()) {
120+
map.put(entry1.getKey(), map.getOrDefault(entry1.getKey(), 0) + entry1.getValue());
121+
}
122+
for (Map.Entry<List<String>, Integer> entry2 : map2.entrySet()) {
123+
map.put(entry2.getKey(), map.getOrDefault(entry2.getKey(), 0) + entry2.getValue());
125124
}
126-
expressions.push(res);
125+
return new Result(map);
127126
}
128127

129-
private String generateTerm(String t1, String t2) {
130-
if (t1.equals("")) {
131-
return t2;
128+
private Result subtract(Result r1, Result r2) {
129+
Map<List<String>, Integer> map1 = r1.getMap();
130+
Map<List<String>, Integer> map2 = r2.getMap();
131+
Map<List<String>, Integer> map = new HashMap<>();
132+
for (Map.Entry<List<String>, Integer> entry1 : map1.entrySet()) {
133+
map.put(entry1.getKey(), map.getOrDefault(entry1.getKey(), 0) + entry1.getValue());
132134
}
133-
if (t2.equals("")) {
134-
return t1;
135+
for (Map.Entry<List<String>, Integer> entry2 : map2.entrySet()) {
136+
map.put(entry2.getKey(), map.getOrDefault(entry2.getKey(), 0) - entry2.getValue());
135137
}
136-
List<String> parts = new ArrayList<>();
137-
Collections.addAll(parts, t1.split("\\*"));
138-
Collections.addAll(parts, t2.split("\\*"));
139-
Collections.sort(parts);
138+
return new Result(map);
139+
}
140+
141+
private Result factor(String s) {
142+
Result res = new Result();
143+
if (s.charAt(i) == '(') {
144+
next(s);
145+
res = expression(s);
146+
next(s);
147+
return res;
148+
}
149+
if (Character.isLowerCase(s.charAt(i))) {
150+
return identifier(s);
151+
}
152+
res.update(new ArrayList<>(), number(s));
153+
return res;
154+
}
155+
156+
private Result identifier(String s) {
157+
Result res = new Result();
140158
StringBuilder sb = new StringBuilder();
141-
for (String part : parts) {
142-
sb.append(part + "*");
159+
while (i < s.length() && Character.isLowerCase(s.charAt(i))) {
160+
sb.append(s.charAt(i));
161+
i++;
143162
}
144-
if (sb.length() > 0) {
145-
sb.setLength(sb.length() - 1);
163+
i--;
164+
next(s);
165+
String variable = sb.toString();
166+
if (evalMap.containsKey(variable)) {
167+
res.update(new ArrayList<>(), evalMap.get(variable));
168+
} else {
169+
List<String> key = new ArrayList<>();
170+
key.add(variable);
171+
res.update(key, 1);
146172
}
147-
return sb.toString();
173+
return res;
148174
}
149175

150-
private static class Expr {
151-
public Map<String, Integer> terms;
176+
private int number(String s) {
177+
int res = 0;
178+
while (i < s.length() && s.charAt(i) >= '0' && s.charAt(i) <= '9') {
179+
res = res * 10 + (s.charAt(i) - '0');
180+
i++;
181+
}
182+
i--;
183+
next(s);
184+
return res;
185+
}
152186

153-
public Expr(String term, int val) {
154-
terms = new HashMap<>();
155-
terms.put(term, val);
187+
private void next(String s) {
188+
i++;
189+
while (i < s.length() && s.charAt(i) == ' ') {
190+
i++;
156191
}
157192
}
158193
}

src/test/java/g0701_0800/s0770_basic_calculator_iv/SolutionTest.java

+8
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,12 @@ void basicCalculatorIV2() {
2525
new int[] {1, 12}),
2626
equalTo(Arrays.asList("-1*pressure", "5")));
2727
}
28+
29+
@Test
30+
void basicCalculatorIV3() {
31+
assertThat(
32+
new Solution()
33+
.basicCalculatorIV("(e + 8) * (e - 8)", new String[] {}, new int[] {}),
34+
equalTo(Arrays.asList("1*e*e", "-64")));
35+
}
2836
}

0 commit comments

Comments
 (0)