Редакция для Удаление повторов
Submitting an official solution before solving the problem yourself is a bannable offence.
1. Идея
Нужно пройти по журналу слева направо и для каждого числа решить: оставить его или удалить.
По условию сохраняется только первое появление каждого значения. Значит:
- если число встретилось впервые — добавляем его в ответ;
- если такое число уже было раньше — пропускаем.
Чтобы быстро понимать, встречалось ли значение раньше, удобно хранить все уже увиденные числа в множестве.
2. Наблюдения
Важен именно порядок первых появлений.
Например, для последовательности
1 2 1 3 2 3 4ответ должен быть1 2 3 4, потому что:1встретилось впервые — оставляем;2встретилось впервые — оставляем;- второе
1— удаляем; 3встретилось впервые — оставляем;- второе
2— удаляем; - второе
3— удаляем; 4встретилось впервые — оставляем.
Если проверять для каждого элемента, встречался ли он раньше, перебором всех предыдущих элементов, получится слишком медленно: до
O(n^2).Множество позволяет проверять наличие элемента в среднем за
O(1), поэтому весь проход по массиву будет работать за линейное время.
3. Алгоритм
- Считать
n. - Считать
nчисел. - Создать:
- множество
seen— значения, которые уже встречались; - список
result— итоговая последовательность.
- множество
- Для каждого числа
x:- если
xне содержится вseen:- добавить
xвseen; - добавить
xвresult.
- добавить
- если
- Вывести элементы
resultв одной строке через пробел.
4. Почему это работает
Докажем, что алгоритм действительно оставляет только первые появления всех значений и сохраняет их порядок.
Рассмотрим произвольное число x.
- Когда
xвстречается в последовательности первый раз, его ещё нет в множествеseen. Значит, алгоритм добавитxвresult. - После этого
xсразу добавляется вseen. - При любом следующем появлении
xоно уже будет вseen, поэтому алгоритм его пропустит.
Значит, каждое значение попадает в ответ ровно один раз — при первом появлении.
Теперь про порядок. Мы идём по входной последовательности слева направо и добавляем элементы в result именно в тот момент, когда впервые их встречаем. Поэтому порядок в ответе совпадает с порядком первых появлений во входных данных.
Следовательно, алгоритм решает задачу правильно.
5. Сложность
- Время работы:
O(n)в среднем, потому что каждый элемент обрабатывается один раз, а операции с множеством выполняются в среднем заO(1). - Память:
O(n), так как в худшем случае все элементы различны и будут храниться и в множестве, и в ответе.
6. Код на C++17
#include <iostream>
#include <vector>
#include <unordered_set>
using namespace std;
int main() {
int n;
cin >> n;
vector<long long> result;
result.reserve(n);
unordered_set<long long> seen;
seen.reserve((size_t)n * 2);
for (int i = 0; i < n; i++) {
long long x;
cin >> x;
if (seen.find(x) == seen.end()) {
seen.insert(x);
result.push_back(x);
}
}
for (int i = 0; i < (int)result.size(); i++) {
if (i > 0) cout << ' ';
cout << result[i];
}
cout << '\n';
return 0;
}
7. Код на Python 3
n = int(input())
a = list(map(int, input().split()))
seen = set()
result = []
for x in a:
if x not in seen:
seen.add(x)
result.append(x)
print(*result)
Комментарии