Skip to content

Commit 870b6b3

Browse files
committed
sprint4
1 parent b55cd57 commit 870b6b3

2 files changed

Lines changed: 434 additions & 0 deletions

File tree

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
import java.io.BufferedInputStream;
2+
import java.io.EOFException;
3+
import java.io.IOException;
4+
import java.io.InputStream;
5+
import java.util.ArrayList;
6+
import java.util.HashMap;
7+
import java.util.HashSet;
8+
import java.util.Map;
9+
import java.util.StringTokenizer;
10+
11+
class FindSystem {
12+
13+
/*
14+
* Принцип работы алгоритма:
15+
* 1) Строим обратный индекс:
16+
* для каждого слова храним список документов, где оно встречается,
17+
* и число его вхождений в каждом документе.
18+
* 2) Для каждого запроса берём только уникальные слова.
19+
* 3) Для каждого такого слова прибавляем его частоту ко всем документам,
20+
* где это слово есть.
21+
* 4) Из найденных документов выбираем 5 лучших:
22+
* сначала по убыванию релевантности, потом по возрастанию номера документа.
23+
*
24+
* Почему алгоритм корректен:
25+
* - В индексе для каждого слова хранится точное число его вхождений в документ.
26+
* - По условию релевантность — это сумма частот всех уникальных слов запроса.
27+
* Именно такую сумму мы и считаем.
28+
* - Повторы слов в запросе не влияют на ответ, потому что мы оставляем только
29+
* уникальные слова запроса.
30+
* - После подсчёта релевантностей выбираем 5 лучших документов по правилу из условия,
31+
* значит ответ получается правильным.
32+
*
33+
* Временная сложность:
34+
* - Построение индекса: O(n), где n — общее число слов во всех документах.
35+
* - Обработка одного запроса: O(n), где n — суммарная длина списков документов
36+
* для уникальных слов запроса.
37+
*
38+
* Пространственная сложность:
39+
* - O(n), где n — число пар (слово, документ) в индексе.
40+
*/
41+
42+
private static HashMap<String, ArrayList<int[]>> buildIndex(String[] docs) {
43+
HashMap<String, ArrayList<int[]>> index = new HashMap<>();
44+
45+
for (int i = 0; i < docs.length; i++) {
46+
HashMap<String, Integer> freq = new HashMap<>();
47+
StringTokenizer st = new StringTokenizer(docs[i]);
48+
49+
while (st.hasMoreTokens()) {
50+
String word = st.nextToken();
51+
freq.put(word, freq.getOrDefault(word, 0) + 1);
52+
}
53+
54+
int docId = i + 1;
55+
for (Map.Entry<String, Integer> entry : freq.entrySet()) {
56+
index.computeIfAbsent(entry.getKey(), k -> new ArrayList<>())
57+
.add(new int[]{docId, entry.getValue()});
58+
}
59+
}
60+
61+
return index;
62+
}
63+
64+
private static String processQuery(String query, HashMap<String, ArrayList<int[]>> index) {
65+
HashSet<String> uniqueWords = new HashSet<>();
66+
StringTokenizer st = new StringTokenizer(query);
67+
68+
while (st.hasMoreTokens()) {
69+
uniqueWords.add(st.nextToken());
70+
}
71+
72+
HashMap<Integer, Integer> relevance = new HashMap<>();
73+
74+
for (String word : uniqueWords) {
75+
ArrayList<int[]> docs = index.get(word);
76+
if (docs == null) {
77+
continue;
78+
}
79+
80+
for (int[] pair : docs) {
81+
int docId = pair[0];
82+
int count = pair[1];
83+
relevance.put(docId, relevance.getOrDefault(docId, 0) + count);
84+
}
85+
}
86+
87+
ArrayList<int[]> best = new ArrayList<>();
88+
89+
for (Map.Entry<Integer, Integer> entry : relevance.entrySet()) {
90+
int docId = entry.getKey();
91+
int score = entry.getValue();
92+
93+
int pos = 0;
94+
while (pos < best.size() && !isBetter(docId, score, best.get(pos)[0], best.get(pos)[1])) {
95+
pos++;
96+
}
97+
98+
if (pos < 5) {
99+
best.add(pos, new int[]{docId, score});
100+
if (best.size() > 5) {
101+
best.remove(5);
102+
}
103+
}
104+
}
105+
106+
StringBuilder sb = new StringBuilder();
107+
for (int i = 0; i < best.size(); i++) {
108+
if (i > 0) {
109+
sb.append(' ');
110+
}
111+
sb.append(best.get(i)[0]);
112+
}
113+
114+
return sb.toString();
115+
}
116+
117+
private static boolean isBetter(int docId1, int score1, int docId2, int score2) {
118+
if (score1 != score2) {
119+
return score1 > score2;
120+
}
121+
return docId1 < docId2;
122+
}
123+
124+
private static void solve() throws Exception {
125+
FastReader reader = new FastReader(System.in);
126+
127+
int n = reader.nextInt();
128+
String[] docs = new String[n];
129+
for (int i = 0; i < n; i++) {
130+
docs[i] = reader.nextLine();
131+
}
132+
133+
HashMap<String, ArrayList<int[]>> index = buildIndex(docs);
134+
135+
int m = reader.nextInt();
136+
StringBuilder out = new StringBuilder();
137+
138+
for (int i = 0; i < m; i++) {
139+
String query = reader.nextLine();
140+
out.append(processQuery(query, index)).append('\n');
141+
}
142+
143+
System.out.print(out);
144+
}
145+
146+
private static void test() {
147+
String[] docs1 = {
148+
"i love coffee",
149+
"coffee with milk and sugar",
150+
"free tea for everyone"
151+
};
152+
153+
HashMap<String, ArrayList<int[]>> index1 = buildIndex(docs1);
154+
assertEquals("1 2", processQuery("i like black coffee without milk", index1));
155+
assertEquals("3", processQuery("everyone loves new year", index1));
156+
assertEquals("2 1", processQuery("Mary likes black coffee without milk", index1));
157+
158+
String[] docs2 = {
159+
"buy flat in Moscow",
160+
"rent flat in Moscow",
161+
"sell flat in Moscow",
162+
"want flat in Moscow like crazy",
163+
"clean flat in Moscow on weekends",
164+
"renovate flat in Moscow"
165+
};
166+
167+
HashMap<String, ArrayList<int[]>> index2 = buildIndex(docs2);
168+
assertEquals("4 5 1 2 3", processQuery("flat in Moscow for crazy weekends", index2));
169+
170+
String[] docs3 = {
171+
"i like dfs and bfs",
172+
"i like dfs dfs",
173+
"i like bfs with bfs and bfs"
174+
};
175+
176+
HashMap<String, ArrayList<int[]>> index3 = buildIndex(docs3);
177+
assertEquals("3 1 2", processQuery("dfs dfs dfs dfs bfs", index3));
178+
System.out.println("Test OK");
179+
}
180+
181+
private static void assertEquals(String expected, String actual) {
182+
if (!expected.equals(actual)) {
183+
throw new AssertionError("expected = [" + expected + "], actual = [" + actual + "]");
184+
}
185+
}
186+
187+
public static void main(String[] args) throws Exception {
188+
if (System.getProperty("os.name").startsWith("Windows")) {
189+
test();
190+
} else {
191+
solve();
192+
}
193+
}
194+
private static class FastReader {
195+
private final InputStream in;
196+
private final byte[] buffer = new byte[1 << 16];
197+
private int ptr = 0;
198+
private int len = 0;
199+
200+
FastReader(InputStream in) {
201+
this.in = new BufferedInputStream(in);
202+
}
203+
204+
private int read() throws IOException {
205+
if (ptr >= len) {
206+
len = in.read(buffer);
207+
ptr = 0;
208+
if (len <= 0) {
209+
return -1;
210+
}
211+
}
212+
return buffer[ptr++];
213+
}
214+
215+
int nextInt() throws IOException {
216+
int c;
217+
do {
218+
c = read();
219+
if (c == -1) {
220+
throw new EOFException();
221+
}
222+
} while (c <= ' ');
223+
224+
int value = 0;
225+
while (c > ' ') {
226+
value = value * 10 + (c - '0');
227+
c = read();
228+
}
229+
return value;
230+
}
231+
232+
String nextLine() throws IOException {
233+
int c = read();
234+
235+
while (c == '\n' || c == '\r') {
236+
c = read();
237+
}
238+
239+
StringBuilder sb = new StringBuilder();
240+
while (c != -1 && c != '\n' && c != '\r') {
241+
sb.append((char) c);
242+
c = read();
243+
}
244+
245+
return sb.toString();
246+
}
247+
}
248+
}

0 commit comments

Comments
 (0)