Подтвердить что ты не робот

Найдите отсутствующие и повторяющиеся элементы в массиве в линейном времени и постоянном пространстве

Вы указали массив из 64-битных целых N. N может быть очень большим. Вы знаете, что каждое целое число 1..N появляется один раз в массиве, за исключением того, что одно целое отсутствует и одно целое дублируется.

Напишите алгоритм линейного времени, чтобы найти отсутствующие и дублированные числа. Кроме того, ваш алгоритм должен работать в небольшом постоянном пространстве и оставить массив нетронутым.

Источник: http://maxschireson.com/2011/04/23/want-a-job-working-on-mongodb-your-first-online-interview-is-in-this-post/

4b9b3361

Ответ 1

Если все числа присутствовали в массиве, сумма была бы N(N+1)/2.

Определите фактическую сумму, суммируя все числа в массиве в O (n), пусть это будет Sum(Actual).

Отсутствует одно число, пусть это будет j, а одно число дублируется, пусть это будет k. Это означает, что

Сумма (фактическая) = N (N + 1)/2 + k - j

полученный из этого

k = Сумма (фактическая) -N (N + 1)/2 + j

Также мы можем вычислить сумму квадратов в массиве, которая суммирует до n 3/3 + n 2/2 + n/6, если присутствовали все числа.

Теперь мы можем вычислить действительную сумму квадратов в O (n), пусть это будет Sum(Actual Squares).

Сумма (Действительные квадраты) = n 3/3 + n 2/2 + n/6 + k 2- j 2

Теперь мы имеем два уравнения, с которыми мы можем определить j и k.

Ответ 2

Трюк XOR работает в два прохода с массивом только для чтения.

Это позволяет избежать проблемы возможного полного переполнения, которое имеет сумма и сумма решения квадратов.

Пусть два числа: x и y, один из которых - это недостающее число, а другое повторяется.

XOR все элементы массива вместе с 1,2,...,N.

Результат w = x XOR y.

Теперь, поскольку x и y различны, w отличен от нуля.

Выберите любой ненулевой бит w. x и y отличаются в этом бите. Скажем, позиция бит k.

Теперь рассмотрим разбиение массива (и числа 1,2,...,N) на два набора, в зависимости от того, бит в позиции k равен 0 или 1.

Теперь, если мы вычислим XOR (отдельно) элементов двух наборов, результат должен быть x и y.

Поскольку критерии расщепления - это просто проверка того, установлен ли бит в нет, мы можем вычислить два XOR двух наборов, сделав другой проход через массив и имеющий две переменные, каждая из которых содержит XOR элементов (и 1,2,...N) для каждого набора. В конце, когда мы закончим, эти две переменные будут содержать x и y.

Связанный:

Ответ 3

Используя основную идею из связанного вопроса интервью, вы можете сделать:

  • Подсчитайте все числа (назовем это S1) и их квадраты (S2)
  • Вычислить ожидаемую сумму чисел без изменений, т.е. E1 = n*(n+1)/2 и E2 = n*(n+1)*(2n+1)/6
  • Теперь вы знаете, что E1 - S1 = d - m и E2 - S2 = d^2 - m^2, где d - это дублированный номер и m отсутствует.
  • Решите эту систему уравнений, и вы обнаружите, что:

    m = 1/2 ((E2 - S2)/(E1 - S1) - (E1 - S1))
    d = 1/2 ((E2 - S2)/(E1 - S1) + (E1 - S1)) // or even simpler: d = m + (E1 - S1)
    

.

$S1 = $S2 = 0;
foreach ($nums as $num) {
    $S1 += $num;
    $S2 += $num * $num;
}

$D1 = $n * ($n + 1) / 2                - $S1;
$D2 = $n * ($n + 1) * (2 * $n + 1) / 6 - $S2;

$m = 1/2 * ($D2/$D1 - $D1);
$d = 1/2 * ($D2/$D1 + $D1);

Ответ 4

Решение, предложенное BrokenGlass, охватывает случай для двух неизвестных (соответствующих одному дублирующему числу и одному отсутствующему числу), используя две формулы:

sum1

и

sum2

Формулы дают обобщенное гармоническое число порядков n -1 и -2 соответственно. (Серия мощности)

Это решение обобщается для трех неизвестных путем включения значения обобщенного гармонического числа порядка n из -3.

sum3

Для решения для m неизвестных (дубликатов и недостающих чисел) используйте m обобщенных гармонических чисел порядков n от -1 до -m.


Морон отмечает, что этот подход обсуждался ранее в StackOverflow на Вопрос о простом интервью стал более сложным.

Ответ 5

Принимая требование leave the array untouched буквально (т.е. массив может быть временно изменен до тех пор, пока он не изменится в конце), может быть предложено ориентированное на программирование решение.

Я предполагаю, что размер массива N намного меньше 2 ^ 64, что является совершенно нереалистичным объемом памяти. Поэтому можно с уверенностью предположить, что N < 2^P такое, что P << 64 (значительно меньше). Другими словами, это означает, что все числа в массиве имеют несколько высоких бит неиспользуемых. Поэтому давайте просто использовать старший бит как флаг, был ли указатель этой позиции замечен в массиве. Алгоритм выглядит следующим образом:

 set HIGH = 2^63  // a number with only the highest bit set
 scan the array, for each number k do
   if array[k] < HIGH: array[k] = array[k] + HIGH // set the highest bit
   else: k is the duplicate
 for each i in 1..N do
   if array[i] < HIGH: i is missing
   else: array[i] = array[i] - HIGH // restore the original number

Это линейное время и очень малое вычисление

Ответ 6

Вот реализация Java, основанная на идее @Aryabhatta:
Вход: [3 1 2 5 3]
Выход: [3, 4]

public ArrayList<Integer> repeatedNumber(final List<Integer> A) {
    ArrayList<Integer> ret = new ArrayList<>();
    int xor = 0, x = 0, y = 0;
    for(int i=0; i<A.size(); i++) {
        xor ^= A.get(i);
    }
    for(int i=1; i<=A.size(); i++) {
        xor ^= i;
    }

    int setBit = xor & ~(xor-1);
    for(int i=0; i<A.size(); i++) {
        if((A.get(i) & setBit) != 0) {
            x ^= A.get(i);
        } else {
            y ^= A.get(i);
        }
    }
    for(int i=1; i<=A.size(); i++) {
        if((i & setBit) != 0) {
            x ^= i;
        } else {
            y ^= i;
        }
    }

    for(int i=0; i<A.size(); i++) {
        if(A.get(i) == x) {
            ret.add(x);
            ret.add(y);
            return ret;
        } 

        if(A.get(i) == y) {
            ret.add(y);
            ret.add(x);
            return ret;
        }
    }

    return ret;
}

Ответ 7

Код Psuedo, предполагающий сортировку набора

missing = nil
duplicate = nil

for i = 0, i < set.size - 1, i += 1
  if set[i] == set[i + 1]
    duplicate = set[i]
  else if((set[i] + 1) != set[i+1])
    missing = set[i] + 1
  if missing != nil && duplicate != nil
    break

return (missing, duplicate)