Skip to content

Commit fb3fdda

Browse files
committed
Calculator
1 parent 4aea0f2 commit fb3fdda

1 file changed

Lines changed: 234 additions & 0 deletions

File tree

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
import java.io.IOException;
2+
import java.io.InputStream;
3+
import java.io.OutputStream;
4+
5+
/*
6+
Принцип работы алгоритма:
7+
- Выражение в обратной польской нотации читается слева направо по токенам (разделитель — пробел).
8+
- Используется стек целых чисел.
9+
* Если токен — число, кладём его в стек.
10+
* Если токен — операция (+, -, *, /), достаём два верхних значения b и a (сначала b, потом a),
11+
вычисляем a (op) b и результат кладём обратно в стек.
12+
- После обработки всех токенов ответ — верхний элемент стека (даже если элементов больше одного).
13+
14+
Корректность:
15+
- Инвариант: после обработки первых i токенов стек содержит значения всех уже полностью вычисленных
16+
подвыражений, которые по правилам ОПН должны ждать дальнейших операций.
17+
- При чтении числа инвариант сохраняется: число становится готовым операндом и помещается в стек.
18+
- При чтении операции по определению ОПН она применяется к двум ближайшим слева операндам,
19+
которые и лежат на вершине стека в нужном порядке добавления. Мы снимаем b и a и кладём результат,
20+
тем самым заменяя эти два операнда на значение их подвыражения — инвариант сохраняется.
21+
- Для деления используется Math.floorDiv(a, b), что соответствует требованию “округление вниз” (floor).
22+
По условию деления на отрицательное число нет, но a может быть отрицательным — floorDiv это корректно обрабатывает.
23+
24+
Оценка сложности:
25+
- Время: O(m), где m — число токенов (каждый токен обрабатывается за O(1)).
26+
- Память: O(s), где s — максимальный размер стека (в худшем случае O(m)).
27+
*/
28+
public class Calculator {
29+
30+
// -------------------- SOLUTION --------------------
31+
static int evalRpn(FastIn in) throws IOException {
32+
IntStack st = new IntStack(64);
33+
34+
String tok;
35+
while ((tok = in.nextOrNull()) != null) {
36+
if (tok.length() == 1) {
37+
char op = tok.charAt(0);
38+
if (op == '+' || op == '-' || op == '*' || op == '/') {
39+
int b = st.pop();
40+
int a = st.pop();
41+
42+
int r;
43+
if (op == '+') {
44+
r = a + b;
45+
} else if (op == '-') {
46+
r = a - b;
47+
} else if (op == '*') {
48+
r = a * b;
49+
} else {
50+
r = Math.floorDiv(a, b);
51+
}
52+
53+
st.push(r);
54+
continue;
55+
}
56+
}
57+
st.push(Integer.parseInt(tok));
58+
}
59+
60+
return st.peek();
61+
}
62+
63+
// -------------------- INT STACK --------------------
64+
static final class IntStack {
65+
private int[] a;
66+
private int sz;
67+
68+
IntStack(int cap) {
69+
this.a = new int[Math.max(2, cap)];
70+
this.sz = 0;
71+
}
72+
73+
void push(int v) {
74+
if (sz == a.length) {
75+
int[] b = new int[a.length << 1];
76+
System.arraycopy(a, 0, b, 0, a.length);
77+
a = b;
78+
}
79+
a[sz++] = v;
80+
}
81+
82+
int pop() {
83+
return a[--sz];
84+
}
85+
86+
int peek() {
87+
return a[sz - 1];
88+
}
89+
}
90+
91+
// -------------------- FAST INPUT --------------------
92+
static final class FastIn {
93+
private final InputStream in;
94+
private final byte[] buf = new byte[1 << 16];
95+
private int ptr = 0, len = 0;
96+
97+
FastIn(InputStream in) {
98+
this.in = in;
99+
}
100+
101+
private int read() throws IOException {
102+
if (ptr >= len) {
103+
len = in.read(buf);
104+
ptr = 0;
105+
if (len <= 0) {
106+
return -1;
107+
}
108+
}
109+
return buf[ptr++];
110+
}
111+
112+
String nextOrNull() throws IOException {
113+
int c;
114+
do {
115+
c = read();
116+
if (c == -1) {
117+
return null;
118+
}
119+
} while (c <= ' ');
120+
121+
byte[] tmp = new byte[32];
122+
int n = 0;
123+
124+
while (c > ' ') {
125+
if (n == tmp.length) {
126+
byte[] t2 = new byte[tmp.length << 1];
127+
System.arraycopy(tmp, 0, t2, 0, tmp.length);
128+
tmp = t2;
129+
}
130+
tmp[n++] = (byte) c;
131+
132+
c = read();
133+
if (c == -1) {
134+
break;
135+
}
136+
}
137+
138+
return new String(tmp, 0, n);
139+
}
140+
}
141+
142+
// -------------------- FAST OUTPUT --------------------
143+
static final class FastOut {
144+
private final OutputStream out;
145+
private final byte[] buf = new byte[1 << 16];
146+
private int p = 0;
147+
private final byte[] tmp = new byte[12];
148+
149+
FastOut(OutputStream out) {
150+
this.out = out;
151+
}
152+
153+
void writeByte(int b) throws IOException {
154+
if (p == buf.length) {
155+
flush();
156+
}
157+
buf[p++] = (byte) b;
158+
}
159+
160+
void writeInt(int x) throws IOException {
161+
if (x == 0) {
162+
writeByte('0');
163+
return;
164+
}
165+
if (x < 0) {
166+
writeByte('-');
167+
x = -x;
168+
}
169+
170+
int k = 0;
171+
while (x > 0) {
172+
tmp[k++] = (byte) ('0' + (x % 10));
173+
x /= 10;
174+
}
175+
for (int i = k - 1; i >= 0; i--) {
176+
writeByte(tmp[i]);
177+
}
178+
}
179+
180+
void flush() throws IOException {
181+
out.write(buf, 0, p);
182+
p = 0;
183+
}
184+
}
185+
186+
private static void run() throws Exception {
187+
FastIn in = new FastIn(System.in);
188+
FastOut out = new FastOut(System.out);
189+
190+
int ans = evalRpn(in);
191+
192+
out.writeInt(ans);
193+
out.writeByte('\n');
194+
out.flush();
195+
}
196+
197+
private static void test() throws Exception {
198+
assertEq(9, evalFromString("2 1 + 3 *"));
199+
assertEq(38, evalFromString("7 2 + 4 * 2 +"));
200+
201+
// деление “вниз”
202+
assertEq(-1, evalFromString("-1 3 /"));
203+
assertEq(-2, evalFromString("-4 3 /"));
204+
205+
// порядок операндов
206+
assertEq(2, evalFromString("10 2 4 * -"));
207+
208+
// одно число
209+
assertEq(5, evalFromString("5"));
210+
211+
System.out.println("Test OK");
212+
}
213+
214+
private static int evalFromString(String s) throws Exception {
215+
InputStream is = new java.io.ByteArrayInputStream(
216+
s.getBytes(java.nio.charset.StandardCharsets.US_ASCII)
217+
);
218+
return evalRpn(new FastIn(is));
219+
}
220+
221+
static void assertEq(int exp, int act) {
222+
if (exp != act) {
223+
throw new AssertionError("Expected=" + exp + ", actual=" + act);
224+
}
225+
}
226+
227+
public static void main(String[] args) throws Exception {
228+
if (System.getProperty("os.name").startsWith("Windows")) {
229+
test();
230+
} else {
231+
run();
232+
}
233+
}
234+
}

0 commit comments

Comments
 (0)