Найти первый уникальный элемент
У меня был этот вопрос в интервью, на который я не мог ответить.
Вы должны найти первый уникальный элемент (целое число) в массиве.
Например:
3,2,1,4,4,5,6,6,7,3,2,3
Тогда уникальные элементы 1, 5, 7
и первые уникальные из 1
.
Требуемое решение:
O (n) Сложность времени.
O (1) Космическая сложность.
Я попробовал сказать:
Использование Hashmaps, Bitvector... но ни одна из них не имела пространственной сложности O (1).
Может ли кто-нибудь сказать мне решение с пространством O (1)?
Ответы
Ответ 1
Здесь нестрогое доказательство того, что это невозможно:
Хорошо известно, что повторное обнаружение не может быть лучше, чем O (n * log n), когда вы используете O (1) пространство. Предположим, что текущая проблема разрешима в O (n) времени и O (1) памяти. Если мы получим индекс "k" первого не повторяющегося числа как ничего, кроме 0, мы знаем, что k-1 повторяется и, следовательно, с еще одной разверткой по массиву, мы можем получить его дубликат, создающий дублирующее обнаружение a O ( n) упражнение.
Снова это не строго, и мы можем попасть в худший анализ, где k всегда 0. Но это помогает вам думать и убеждать интервьюера, что это вряд ли возможно.
http://en.wikipedia.org/wiki/Element_distinctness_problem говорит:
Элементы, которые встречаются больше n/k раз в мультимножестве размера n, могут быть найдены за время O (n log k). Здесь k = n, так как мы хотим, чтобы элементы отображались более одного раза.
Ответ 2
Я думаю, что это невозможно. Это не доказательство, а доказательство гипотезы. Мои рассуждения таковы:
Сначала вы сказали, что нет никакой привязки к значению элементов (они могут быть отрицательными, 0 или положительными). Во-вторых, существует только пробел O(1)
, поэтому мы не можем хранить больше фиксированного количества значений. Следовательно, это означает, что мы должны решить это, используя только сравнения. Более того, мы не можем сортировать или иным образом менять значения в массиве, потому что мы потеряем первоначальный порядок уникальных значений (и мы не сможем сохранить исходный порядок).
Рассмотрим массив, где все целые числа уникальны:
1, 2, 3, 4, 5, 6, 7, 8, 9, 10
Чтобы вернуть верный вывод 1
в этом массиве без переупорядочения массива, нам нужно сравнить каждый элемент со всеми остальными элементами, чтобы убедиться, что он уникален и сделать это в обратном порядке, поэтому мы можем проверить первый уникальный элемент последним. Для этого потребовалось бы сравнение O(n^2)
с пространством O(1)
.
Я удалю этот ответ, если кто-нибудь найдет решение, и я приветствую любые указатели на то, чтобы сделать это более строгим доказательством.
Ответ 3
Примечание: Это не может работать в общем случае. См. Рассуждения ниже.
Оригинальная идея
Возможно, есть решение в O (n) времени и O (1) дополнительное пространство.
Можно построить кучу в O (n) времени. См. Построение кучи.
Итак, вы построили кучу назад, начиная с последнего элемента в массиве и сделав последнюю позицию корнем. При создании кучи отслеживайте самый последний элемент, который не был дублированным.
Это предполагает, что при вставке элемента в кучу вы столкнетесь с любым идентичным элементом, который уже существует в куче. Я не знаю, смогу ли я это доказать.,.
Предполагая, что вышесказанное верно, тогда, когда вы закончите создание кучи, вы знаете, какой элемент был первым не дублированным элементом.
Почему это не сработает
Алгоритм построения кучи на месте начинается в середине массива и предполагает, что все узлы за этой точкой являются листовыми узлами. Затем он работает назад (по направлению к пункту 0), просеивая предметы в кучу. Алгоритм не проверяет последние n/2 позиции в каком-либо конкретном порядке, и порядок изменяется, поскольку элементы отфильтровываются в кучу.
В результате лучшее, что мы могли бы сделать (и даже тогда я не уверен, что мы могли бы сделать это надежно), находит первый не дублированный элемент, только если он встречается в первой половине массива.
Ответ 4
В оригинале ОП не упоминается предел числа (хотя последнее добавление числа может быть отрицательным/положительным/нулевым). Здесь я предполагаю еще одно условие:
Число в массиве меньше длины массива и неотрицательным.
Тогда, давая O (n) время, возможно решение O (1) пространства и представляется как вопрос интервью, и тестовый пример OP дает в вопросе соответствие вышеприведенному предположению.
Решение:
for (int i = 0; i < nums.length; i++) {
if (nums[i] != i) {
if (nums[i] == -1) continue;
if (nums[nums[i]] == nums[i]) {
nums[nums[i]] = -1;
} else {
swap(nums, nums[i], i);
i--;
}
}
}
}
for (int i = 0; i < nums.length; i++) {
if (nums[i] == i) {
return i;
}
}
Алгоритм здесь рассматривает исходный массив как ведро в сортировке ведра. Поместите числа в свое ведро, если их более двух раз, отметьте как -1. Используя другой цикл, чтобы найти первое число с числами [i] == i