Предыдущее 65-байтовое решение:
r->{for(int a,b=0,z,i=0;;b=a)if((a=b|1<<(z=r[i++]))==b)return z;}
Новое решение 19 байтов включены дляimport java.math.*;
-8 байт благодаря @Nevay
r->{int z,i=0;for(BigInteger c=BigInteger.ZERO;c.min(c=c.setBit(z=r[i++]))!=c;);return z;}
Попробуйте онлайн!
редактировать
Алгоритм в моей исходной программе был в порядке, но статический размер используемого типа данных означал, что он сломался довольно быстро, как только размер превысил определенный порог.
Я изменил тип данных, используемый в вычислениях, чтобы увеличить лимит памяти программы, чтобы приспособиться к этому (используя BigIntegerдля произвольной точности вместо intили long). Однако, это делает спорным, считается ли это O(1)сложностью пространства.
Я оставлю свое объяснение ниже без изменений, но я хочу добавить, что теперь я считаю, что невозможно достичь O(1)космической сложности без некоторых предположений.
доказательство
Определите Nкак целое число такое, что 2 <= N.
Позвольте Sбыть список, представляющий ряд случайных целых чисел [x{1}, ..., x{N}], где x{i}имеет ограничение 1 <= x{i} <= N.
Сложность по времени (в обозначениях Big-O), необходимая для итерации по этому списку ровно один раз для каждого элемента, равна O(n)
Задача состоит в том, чтобы найти первое дублированное значение в списке. Более конкретно, мы ищем первое значение, Sкоторое является дубликатом предыдущего элемента в списке.
Позвольте pи qбыть позиции двух элементов в списке, что p < qи x{p} == x{q}. Наша задача - найти самое маленькое q, удовлетворяющее этим условиям.
Очевидный подход к этой проблеме - перебрать S и проверить, x{i}существует ли наш объект в другом списке T: если x{i}его нет в T, мы сохраняем его в T. Если x{i}существует в T, это первое дублирующее значение и, следовательно, наименьшее q, и как таковое мы возвращаем его. Эта космическая эффективность есть O(n).
Чтобы достичь O(1)пространственной сложности при сохранении O(n)временной сложности, мы должны хранить уникальную информацию о каждом объекте в списке в ограниченном количестве пространства. Из-за этого единственный способ, которым любой алгоритм мог работать вO(1)Сложность пространства заключается в том, что: 1. N задана верхняя граница, соответствующая памяти, необходимой для хранения максимального количества возможных значений для конкретного конечного типа данных. 2. Переназначение одной неизменяемой переменной не учитывается в зависимости от сложности, а только от количества переменных (список состоит из нескольких переменных). 3. (Основано на других ответах) Список (или, по крайней мере, элементы списка) изменчив, а тип данных списка предварительно задан как целое число со знаком, что позволяет вносить изменения в элементы, находящиеся далее в списке. без использования дополнительной памяти.
1 и 3 требуют предположений и спецификаций о типе данных, в то время как 2 требует, чтобы при расчете сложности пространства учитывалось только количество переменных, а не их размер. Если ни одно из этих допущений не будет принято, было бы невозможно достичь как O(n)временной, так и O(1)пространственной сложности.
объяснение
Черт возьми, этот занял смущающе много времени, чтобы придумать немного умственных способностей.
Итак, идти за бонусом сложно. Нам нужно одновременно работать со всем списком ровно один раз и отслеживать, какие значения мы уже перебрали, без дополнительной сложности с пространством.
Битовая манипуляция решает эти проблемы. Мы инициализируем наше O(1)«хранилище», пару целых чисел, затем выполняем итерацию по списку, ИЛИ вставляем i-й бит в наше первое целое число и сохраняем этот результат во втором.
Например, если у нас есть 1101, и мы выполняем операцию ИЛИ 10, мы получаем 1111. Если мы сделаем еще одно ИЛИ с нами 10, у нас все еще будет 1101.
Поэтому, как только мы выполним операцию ИЛИ и получим тот же номер, мы нашли наш дубликат. Отсутствие дубликатов в массиве приводит к тому, что программа запускается и выдает исключение.