Вопрос интервью по решению проблем (массивы)

Существует массив целых чисел, скажем 3,5,7,9. Вы должны создать другой массив и заполнить его таким образом, чтобы вторая позиция 0-го массива была произведением всех чисел из первого массива, исключая число на его 0-й позиции, то есть оно должно быть 5x7x9 (исключая 3), число в индексе 1 второго массива будет произведение 3x7x9 (исключая 5).

Первый ответ, который пришел мне на ум, состоял из 2 циклов, которые приведут к временной сложности O (n2). Позже я понял это:

Умножая все числа в первом массиве (3x5x7x9), и при заполнении второго массива я делю этот продукт на число в этой позиции. разделите на 3, если я заполняю 0-ю позицию, разделите на 5, если я заполняю 1-ю позицию и так далее. Это снизит сложность от O (n2) до, вероятно, O (2n).

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

Ответ 1

Я не уверен, что вопрос о пространстве или о самом решении. Поскольку все предлагали решения, это заставляет меня думать, что они не понимают решения интервьюера, поэтому вот объяснение:

Мы поддерживаем два массива. Первое, запущенное произведение чисел исходного массива. Таким образом, элемент в месте i будет произведением первых элементов i в исходном массиве (без латекса, но запись i th имеет значение it pi{j=0 to i} j). Второй массив - это просто обратное направление, поэтому запись i th будет иметь значение: pi{j=N-i to N} j.

Чтобы построить требуемый конечный массив, мы просто запускаем каждый из наших двух массивов и умножаем записи. Таким образом, значение i th в конечном массиве будет произведением всех записей, которое является произведением от 0 до i-1 умножить произведение i+1 на N, который является произведением первой записи массива i-1 и второй записи массива i+1.

Общее время и пространство O(n)

Ответ 2

  • Храните элементы с 1 по я в массив A, с A[i]являясь произведением элемента 1 на элемент i;

  • Храните элементы i-n (размер ввода) в массив B, причем B[i] является произведением элемента я в элемент n;

  • Когда нужен результат [i], используйте A [i-1] * B [i + 1]. Угловые корпуса тривиальным образом, просто используйте B [1] и A [n-2] (при этом A [n-1] является последним элемент).

Ответ 3

Я думаю, что могу сделать это в O (n log n).

Храните продукт первой половины номеров и второй половины номеров.

Также сохраняйте продукт первого квартала, второго квартала, третьего квартала и четвертого квартала.

Также сохраните продукт первой восьмой, второй восьмой, восьмой восьмой.

И так далее.

Вы можете построить это с нуля, вычислив произведение каждой пары, затем произведение каждой из этих пар и т.д.

Общее количество дополнительных данных здесь O (n) и принимает O (n) для вычисления (легко показать).

Теперь, чтобы вычислить результат для (скажем) элемента 0, вы берете произведение второй половины, произведение второй четверти (т.е. вторую половину первой четверти), произведение второй половины первый восьмой и т.д., и умножьте их вместе. Существует log n таких чисел, поэтому эта операция является log n.

Чтобы вычислить произведение для элемента k, напишите k в бинарном файле и переверните его биты. Высокий бит затем сообщает вам, с какой половины начать; следующий бит сообщает вам, какая половина оставшейся половины используется следующей; следующий бит говорит вам, какая половина оставшейся четверти для использования следующей; и т.д.

Таким образом, любой выходной элемент можно вычислить в log n времени. Сделайте это для каждого из n выходных элементов, и вы получите O (n log n).

[править]

Конечно, также работает подход "вперед и назад". Думаю, я должен внимательно прочитать вопрос.: -)

[edit 2]

Что касается решения интервьюера (и davin), вам фактически не нужно создавать дополнительный массив... Предполагая, что вы можете редактировать значения в выходном массиве.

Сначала построим выходной массив B такой, что B [i] = A [0] A [1]... * A [i-1] и B [0] = 1. Вы можете сделать это постепенно, поэтому это линейное время:

B[0] = 1;
for (i=1 ; i < n ; ++i) {
    B[i] = B[i-1] * A[i];
}

Затем сканирование назад с n-2 для вычисления ответов, отслеживание "продукта до сих пор":

x = A[n-1];
for (j=n-2 ; j >= 0 ; ++j) {
    B[j] *= x;
    x *= A[j];
}

Это решает проблему в O (n) без создания дополнительного массива.

Ответ 4

Я считаю, что он имел в виду, что, учитывая массив A = {a_1,..., a_n}, он создаст два новых массива:

F_A = {a_1, a_1 * a_2,..., a_1 *... * a_n}

который может быть построен в линейном времени, поддерживая кумулятивный продукт, итерации вперед по массиву, и

B_A = {a_1 *... * a_n,..., a_n * a_ (n-1), a_n}

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

Теперь, чтобы заполнить индекс я в массиве результатов, вы просто умножаете F_A [i-1] на B_A [i + 1]:

F_A [i-1] * B_A [i + 1] = [a_1 *... * a_ (i-1)] * [a_ (i + 1) *... * a_n]

Ответ 5

Как насчет абсурда Логарифма. Вместо деления вы вычитаете?

Но если вы можете изменить 1-й массив, вы можете сделать что-то вроде

//pop arr2
r=1
for(i=len-1;i>=0;i--)
{
   r=r*arr1[i]
   arr2[i]=r
}

//modify arr1
r=1
for(i=0;i<len;i++)
{
   r=r*arr1[i]
   arr1[i]=r
}

//fix arr2
arr2[0]=arr2[1];
for(i=1;i<len-1;i--)
{
     arr2[i]=arr2[i+1]*arr1[i-1];
}
arr2[len-1]=arr1[len-2];