https://leetcode.com/problems/contains-duplicate/
Вернуть true, если список содержит дубликаты, и false, если все элементы уникальны. До 100 тысяч элементов в диапазоне 32-битного знакового целого числа.
Тут даже аудитория видеокурсов знает, что надо сделать set, запихать в него элементы и сравнить его длину с длиной массива. Только самые дремучие будут бегать по массиву двойным циклом за O(n²), впрочем, сэкономив при этом изрядно памяти.
Думал, сейчас за пару минут решу и дальше пойду. Но что-то пошло не по плану.
class Solution {
public:
bool containsDuplicate(vector& nums) {
unordered_set nset;
nset.reserve(nums.size() / 2);
for (const auto n : nums) {
if (nset.contains(n)) return true;
nset.insert(n);
}
return false;
}
};
Я разве не зарезервировал место, предотвращая частую реаллокацию с перемещением элементов? Разве тут нет раннего выхода по первому дубликату? Что в этом коде вообще лишнее?Вспомнился розыгрыш с какого-то радио 20-летней давности, где крутили 4 вопроса:
1) Это же hash set?
2) У него ведь линейная сложность?
3) А почему я тогда получаю такие результаты?

И дальше - к п. 1.
Заметим, это была лучшая из 6 попыток, остальные доходили до 112ms и 65%.
И, наконец, переходим к вопросу.
Как это нужно решать, чтобы получить хотя бы вот такой результат?

Т.е. время выполнения снижено почти вдвое, а футпринт памяти - на 10 мегов.
Смотрел солюшены, люди не понимают разницы между std::set и std::unordered_set, а большинство бегает по массиву теми самыми циклами за O(n²).
Сразу скажу, что коварство литкода в тестовых данных этой "лёгкой" задачи превосходит даже их обычные традиции. Есть кейсы с очень длинными списками. Есть кейсы с данными, специально подобранными для максимизации коллизий в STL hash set, например, отличающимися на один бит в средних разрядах (так обходят внутреннее дополнительное хеширование старших разрядов в младшие). Естественно, как и во всех прочих тестах, присутствуют INT_MIN, INT_MAX, так что надеяться на ограниченность диапазона элементов не стоит.
Кстати, можно было бы попробовать выбором Хоара: это частичная сортировка с ранним выходом. В другой задаче я такое применял. Но в худшем случае - всё равно будет O(n log n), т.к. весь массив придётся отсортировать.
https://leetcode.com/problems/contains-duplicate/submissions/1031795370/
А минимум памяти - 57.101 Мб (на алгоритме с сортировкой как раз). Меньше было бы только у квадратичного алгоритма, но не проходит по лимиту времени. Может, есть какое-то шаманство, отключение каких-то буферов рантайма... Будет время - попробую полазить по решениям других тестов.