Проверьте, является ли массив B перестановкой A

Я попытался найти решение для этого, но не мог сильно уйти из головы.

Нам даны два несортированных целочисленных массива A и B. Нам нужно проверить, является ли массив B перестановкой A. Как это можно сделать? Даже XORing числа не будут работать, так как может быть несколько контрпримеров, которые имеют одинаковое значение XOR bt, не являются перестановкой друг друга.

Решением должно быть время O (n) и с пространством O (1)

Любая помощь приветствуется! Спасибо.

Ответ 1

Вопрос теоретический, но вы можете сделать это в O (n) времени и o (1) пространстве. Выделите массив из 2 32 счетчиков и установите их равными нулю. Это шаг O (1), потому что массив имеет постоянный размер. Затем итерации через два массива. Для массива A увеличивайте счетчики, соответствующие прочитанным целым числам. Для массива B уменьшите их. Если во время итерации массива B вы столкнулись с отрицательным значением счетчика, остановите --- массивы не являются перестановками друг друга. В противном случае в конце (если A и B имеют одинаковый размер, предпосылка), массив счетчиков равен нулю, а два массива являются перестановками друг друга.

Это O (1) пространство и O (n) решение времени. Однако это непрактично, но легко пройдет как решение вопроса интервью. По крайней мере, это должно быть.

Более неясные решения

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

  • В рандомизированной модели вычислений постройте случайную коммутативную хэш-функцию и вычислите значения хэша для двух массивов. Если значения хэша различаются, массивы не являются перестановками друг друга. В противном случае они могут быть. Повторите много раз, чтобы довести вероятность ошибки ниже желаемого порога. Также на O (1) пространстве O (n) подход времени, но рандомизированный.

  • В параллельной вычислительной модели пусть 'n' будет размером входного массива. Выделите 'n' потоков. Каждый поток я = 1.. n считывает i-й номер из первого массива; пусть это будет х. Затем один и тот же поток подсчитывает количество вхождений x в первом массиве, а затем проверяет одинаковый счет во втором массиве. Каждый поток использует O (1) пространство и O (n) время.

  • Интерпретируйте целочисленный массив [a1,..., an] как многочлен x a1 + x a2 +... + x an где x - свободная переменная, а проверка - численно для эквивалентности полученных двух многочленов. Используйте арифметику с плавающей запятой для O (1) пространства и времени O (n). Неточный метод из-за ошибок округления и потому, что числовая проверка эквивалентности вероятностна. Альтернативно, интерпретируем многочлен над целыми числами по модулю простого числа и выполняем ту же вероятностную проверку.

Ответ 2

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

Для обоих массивов вычислим произведение Prime [i] для каждого целого числа i, где Prime [i] является i-м простым числом. Значения продуктов массивов равны, если они являются перестановками друг друга.

Первичная факторизация помогает здесь по двум причинам.

  • Умножение транзитивно, поэтому упорядочение операндов для вычисления произведения не имеет значения. (Некоторые ссылались на то, что, если массивы были отсортированы, эта проблема была бы тривиальной. Путем умножения мы неявно сортируем.)
  • Основные числа умножаются без потерь. Если нам дано число и сказано, что это произведение только простых чисел, мы можем точно рассчитать, какие простые числа были введены в него и сколько именно.

Пример:

a = 1,1,3,4
b = 4,1,3,1
Product of ith primes in a = 2 * 2 * 5 * 7 = 140
Product of ith primes in b = 7 * 2 * 5 * 2 = 140

Тем не менее, нам, вероятно, не разрешен доступ к списку простых чисел, но это кажется хорошим решением в противном случае, поэтому я думал, что опубликую его.

Ответ 3

Приносим извинения за отправку этого ответа в качестве ответа, так как это должен быть комментарий к запросу antti.huima, но у меня еще нет репутации, чтобы комментировать.

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

Например, пусть входной массив A равен 1 с длиной (2 ^ 32) + 1. Для этого потребуется счетчик размером 33 бита (который на практике удваивает размер массива, но оставайтесь с теорией). Двойной размер A (все еще 1 значение), и вам нужно 65 бит для каждого счетчика и т.д.

Это очень ничтожный аргумент, но эти вопросы интервью, как правило, очень ничтожны.

Ответ 4

Если нам не нужно сортировать это на месте, тогда может работать следующий подход:

  • Создайте элемент HashMap, Key as array, Value как количество событий. (Для обработки нескольких вхождений одного и того же номера)
  • Аргумент перемещения A.
  • Вставьте элементы массива в HashMap.
  • Далее, перемещаем массив B.
  • Поиск каждого элемента B в HashMap. Если соответствующее значение равно 1, удалите запись. Иначе, уменьшите значение на 1.
  • Если мы сможем обрабатывать весь массив B, а HashMap в это время пуст, "Успех". else Failure.

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

Не уверен, что это то, что вы ищете. Дайте мне знать, если я пропустил какое-либо ограничение пространства/времени.

Ответ 5

У вас есть два ограничения: вычислительный O (n), где n означает общую длину как A, так и B и памяти O (1).

Если две серии A, B являются перестановками друг друга, то также является серией C в результате перестановки либо A, либо B. Таким образом, проблема заключается в том, чтобы перевести как A, так и B в ряды C_A и C_B и сравнить их.

Одна такая перестановка будет сортировать. Существует несколько алгоритмов сортировки, которые работают на месте, поэтому вы можете сортировать A и B на месте. Теперь в лучшем случае Smooth Sort сортирует с O (n) вычислительной и O (1) сложностью памяти, в худшем случае с O (n log n)/O (1).

Сравнение элементов в элементе затем выполняется в O (n), но поскольку в O-нотации O (2 * n) = O (n), используя Smooth Sort и сравнение, вы получите O (n)/O (1 ) проверьте, являются ли две серии перестановками друг друга. Однако в худшем случае это будет O (n log n)/O (1)

Ответ 6

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

Если у вас есть доступ к списку простых чисел, вы делаете это как решение проблемы.

Примечание. Если интервьюер говорит, что у вас нет доступа к списку простых номеров. Затем сгенерируйте простые числа и сохраните их. Это O (1), потому что длина алфавита является постоянной.

Иначе вот моя альтернативная идея. Для простоты я буду определять алфавит как = {a, b, c, d, e}. Значения для букв определяются как:

a, b, c, d, e
1, 2, 4, 8, 16

Примечание: если интервьюер говорит, что это не разрешено, тогда создайте таблицу поиска для алфавита, это займет пространство O (1), потому что размер алфавита является константой

Определите функцию, которая может найти различные буквы в строке.

// set bit value of char c in variable i and return result
distinct(char c, int i) : int

E.g. distinct('a', 0) returns 1
E.g. distinct('a', 1) returns 1
E.g. distinct('b', 1) returns 3

Таким образом, если вы повторяете строку "aab", то отдельная функция должна дать 3 в качестве результата

Определите функцию, которая может вычислять сумму букв в строке.

// return sum of c and i
sum(char c, int i) : int

E.g. sum('a', 0) returns 1
E.g. sum('a', 1) returns 2
E.g. sum('b', 2) returns 4

Таким образом, если вы повторяете строку "aab", функция sum должна дать 4 в качестве результата

Определите функцию, которая может вычислять длину букв в строке.

// return length of string s
length(string s) : int

E.g. length("aab") returns 3

Запуск методов в двух строках и сравнение результатов занимает время O (n). Сохранение значений хэша принимает O (1) в пространстве.

 e.g. 
 distinct of "aab" => 3
 distinct of "aba" => 3
 sum of "aab => 4
 sum of "aba => 4
 length of "aab => 3
 length of "aba => 3

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

EDIT. Решения не соответствуют указанным значениям алфавита, указанным в комментариях.

Ответ 7

Вы можете преобразовать один из двух массивов в хэш-таблицу на месте. Это не будет точно O (N), но оно будет близко, в непатологических случаях.

Просто используйте [число% N] в качестве желаемого индекса или в цепочке, которая начинается там. Если какой-либо элемент необходимо заменить, его можно поместить в индекс, где начался оскорбительный элемент. Промыть, промыть, повторить.

UPDATE: Это аналогичная (N = M) хеш-таблица. Она использовала цепочку, но ее можно было понизить до открытой адресации.

Ответ 8

Я бы использовал рандомизированный алгоритм с низкой вероятностью ошибки.

Ключ должен использовать универсальную хэш-функцию .

def hash(array, hash_fn):
  cur = 0
  for item in array:
    cur ^= hash_item(item)
  return cur

def are_perm(a1, a2):
  hash_fn = pick_random_universal_hash_func()
  return hash_fn(a1, hash_fn) == hash_fn(a2, hash_fn) 

Если массивы являются перестановками, это всегда будет правильным. Если они различны, алгоритм может неправильно сказать, что они одинаковы, но он будет делать это с очень низкой вероятностью. Кроме того, вы можете получить экспоненциальное уменьшение вероятности ошибки с линейным объемом работы, задав много вопросов is_perm() на одном и том же входе, если он когда-либо говорит "нет", то они определенно не являются перестановками друг друга.

Ответ 9

Я просто нашел контрпример. Итак, приведенное ниже предположение неверно.


Я не могу это доказать, но я думаю, что это может быть правдой.

Поскольку все элементы массивов являются целыми числами, предположим, что каждый массив имеет 2 элемента, и мы имеем

a1 + a2 = s
a1 * a2 = m

b1 + b2 = s
b1 * b2 = m

then {a1, a2} == {b1, b2}

если это так, это верно для массивов, имеющих n-элементов.

Итак, мы сравниваем сумму и произведение каждого массива, если они равны, одна - это перестановка другого.