Мне задали этот вопрос на собеседовании, и я хотел бы знать, как другие решат его. Мне больше всего нравится Java, но приветствуются решения на других языках.
Если дан массив чисел,
nums
вернуть массив чиселproducts
, гдеproducts[i]
произведение всехnums[j], j != i
.Input : [1, 2, 3, 4, 5] Output: [(2*3*4*5), (1*3*4*5), (1*2*4*5), (1*2*3*5), (1*2*3*4)] = [120, 60, 40, 30, 24]
Вы должны сделать это
O(N)
без использования деления.
[interview-questions]
тег в поисках этого. У вас есть ссылка, если вы нашли ее?Ответы:
Объяснение метода полигенных смазок таково : хитрость заключается в построении массивов (в случае 4 элементов)
И то, и другое можно сделать в O (n), начиная с левого и правого краев соответственно.
Затем умножение двух элементов массива на элемент дает требуемый результат
Мой код будет выглядеть примерно так:
Если вам нужно быть O (1) в космосе, вы можете сделать это (что менее понятно, ИМХО)
источник
v_i=0
тогда единственная ненулевая запись в результате - это i-й элемент. Однако я подозреваю, что добавление прохода для обнаружения и подсчета нулевых элементов может отвлечь от ясности решения и, вероятно, не принесет никакого реального прироста производительности в большинстве случаев ..Вот небольшая рекурсивная функция (в C ++) для выполнения модификации на месте. Это требует O (n) дополнительного пространства (в стеке). Предполагая, что массив находится в a, а N содержит длину массива, мы имеем
источник
num[N-1]
; затем на обратном пути он вычисляет вторую часть умножения, которая затем используется для изменения массива чисел на месте.Вот моя попытка решить это на Java. Извините за нестандартное форматирование, но в коде много дублирования, и это лучшее, что я могу сделать, чтобы сделать его читабельным.
Инварианты цикла - это
pi = nums[0] * nums[1] *.. nums[i-1]
иpj = nums[N-1] * nums[N-2] *.. nums[j+1]
.i
Часть слева есть «префикс» логика, аj
часть по праву является «суффикс» логикой.Рекурсивный однострочный
Жасмит дала (красивое!) Рекурсивное решение; Я превратил это в эту (отвратительную!) Java-строку. Это делает модификацию на месте , с
O(N)
временным пространством в стеке.источник
Перевод решения Майкла Андерсона на Хаскелл:
источник
Скрытно обходя правило «без делений»:
источник
Вот, пожалуйста, простое и чистое решение со сложностью O (N):
источник
C ++, O (n):
источник
На)
источник
Вот мое решение в современном C ++. Он использует
std::transform
и довольно легко запомнить.Код онлайн (wandbox).
источник
Это O (n ^ 2), но f # оооочень красиво:
источник
Просчитайте произведение чисел слева и справа от каждого элемента. Для каждого элемента желаемое значение является продуктом продуктов его соседей.
Результат:
(ОБНОВЛЕНИЕ: теперь я посмотрю поближе, в нем используется тот же метод, что и у Майкла Андерсона, Даниеля Миговски и вышеупомянутых полигенасыщенных смазок)
источник
Tricky:
Используйте следующее:
Да, я уверен, что пропустил i-1 вместо i, но это способ решить эту проблему.
источник
Также существует O (N ^ (3/2)) неоптимальное решение. Это довольно интересно, хотя.
Сначала необходимо предварительно обработать каждое частичное умножение размером N ^ 0.5 (это делается за O (N) временной сложности). Затем вычисление для кратного числа других значений каждого числа может быть выполнено за 2 * O (N ^ 0.5) времени (почему? Потому что вам нужно только умножить последние элементы других ((N ^ 0.5) - 1) чисел, и умножьте результат на ((N ^ 0.5) - 1) числа, которые принадлежат группе текущего числа). Делая это для каждого числа, можно получить O (N ^ (3/2)) время.
Пример:
4 6 7 2 3 1 9 5 8
частичные результаты: 4 * 6 * 7 = 168 2 * 3 * 1 = 6 9 * 5 * 8 = 360
Чтобы вычислить значение 3, нужно умножить значения других групп 168 * 360, а затем на 2 * 1.
источник
Это решение, которое я придумал, и я нашел его настолько ясным, что вы думаете !?
источник
arr = [1, 2, 3, 4, 5] prod = [] productify (arr, prod, 0) print prod
источник
Для полноты вот код в Scala:
Это распечатает следующее:
Программа отфильтрует текущий элемент (_! = Elem); и умножить новый список с помощью метода reduLeft. Я думаю, что это будет O (n), если вы используете scala view или Iterator для lazy eval.
источник
На основании ответа Билла - извините, я не могу комментировать, но вот версия scala, которая правильно обрабатывает дублирующиеся элементы в списке, и, вероятно, O (n):
возвращает:
источник
Добавляя мое решение JavaScript здесь, я не нашел никого, кто предлагал бы это. Что нужно разделить, кроме как посчитать, сколько раз вы можете извлечь число из другого числа? Я провел вычисление произведения всего массива, а затем перебрал все элементы и вычел текущий элемент до нуля:
источник
Я пользуюсь C #:
источник
Мы можем сначала исключить
nums[j]
(гдеj != i
) из списка, а затем получить произведение остальных;python way
Чтобы решить эту загадку, необходимо выполнить следующее:источник
Ну, это решение можно считать решением C / C ++. Допустим, у нас есть массив «a», содержащий n элементов, таких как [n], тогда псевдокод будет таким, как показано ниже.
источник
Еще одно решение, используя разделение. с двойным обходом. Умножьте все элементы и затем начните делить их на каждый элемент.
источник
источник
Вот мой код:
источник
Вот немного функциональный пример с использованием C #:
Я не совсем уверен, что это O (n) из-за полу-рекурсии созданных Funcs, но мои тесты, похоже, показывают, что это O (n) во времени.
источник
// Это рекурсивное решение в Java // Вызывается следующим образом из основного продукта (a, 1,0);
источник
Оптимальное решение с O (n) временем выполнения:
Создайте окончательный массив «result» для элемента i,
источник
источник
Вот еще одна простая концепция, которая решает проблему в
O(N)
.источник
У меня есть решение с
O(n)
пространственно-O(n^2)
временной сложностью, представленное ниже,источник