Обычная задача в программировании интервью (хотя не из моего опыта интервью) состоит в том, чтобы взять строку или целое число и перечислить каждую возможную перестановку.
Есть ли пример того, как это делается, и логика решения такой проблемы?
Я видел несколько фрагментов кода, но они не были хорошо прокомментированы / объяснены и, следовательно, трудны для понимания.
c#
algorithm
permutation
GurdeepS
источник
источник
Ответы:
Прежде всего: конечно, пахнет рекурсией !
Поскольку вы также хотели знать этот принцип, я приложил все усилия, чтобы объяснить его на человеческом языке. Я думаю, что рекурсия в большинстве случаев очень проста. Вам нужно только понять два шага:
На человеческом языке :
Я нашел псевдокод на http://www.programmersheaven.com/mb/Algorithms/369713/369713/permutation-algorithm-help/ :
C #
Хорошо, и что-то более сложное (и так как он помечен c #), от http://radio.weblogs.com/0111551/stories/2002/10/14/permutations.html : довольно долго, но я решил скопировать его во всяком случае, поэтому пост не зависит от оригинала.
ABC, ACB, BAC, BCA, CAB, CBA.
Код:
источник
Swap(ref list[k], ref list[i]);
) не нужен.(a[x], a[y]) = (a[y], a[x]);
Это всего лишь две строки кода, если LINQ разрешено использовать. Пожалуйста, посмотрите мой ответ здесь .
РЕДАКТИРОВАТЬ
Вот моя общая функция, которая может возвращать все перестановки (не комбинации) из списка T:
Пример:
Вывод - список целочисленных списков:
Поскольку эта функция использует LINQ, для нее требуется .net 3.5 или выше.
источник
const string s = "HALLOWEEN";
var result = GetPermutations(Enumerable.Range(0, s.Length), s.Length).Select(t => t.Select(i => s[i]));
Здесь я нашел решение. Он был написан на Java, но я преобразовал его в C #. Я надеюсь, что это поможет вам.
Вот код в C #:
источник
Рекурсия не нужна, вот хорошая информация об этом решении.
Я использовал этот алгоритм в течение многих лет, он имеет O (N) сложность времени и пространства для расчета каждой перестановки .
источник
O(N-1)
для последовательности иO(N)
для перестановокO(N)
. И я все еще использую это в производстве, но с рефакторингом, чтобы генерировать только одну перестановку, например:GetPermutation(i)
где0 <= i <= N!-1
. Я буду рад использовать что-то с лучшей производительностью, чем эта, так что будьте свободны называть ссылку для чего-то лучшего, большинство альтернатив используютO(N!)
в памяти, так что вы можете проверить это тоже.Вы можете написать свою функцию подкачки, чтобы поменять символы.
Это должно называться permute (string, 0);
источник
Прежде всего, наборы имеют перестановки, а не строки или целые числа, поэтому я просто предположу, что вы имеете в виду «набор символов в строке».
Обратите внимание, что набор размера n имеет n! п-перестановки.
Следующий псевдокод (из Википедии), вызываемый с k = 1 ... n! даст все перестановки:
Вот эквивалентный код Python (для индексов массива на основе 0):
источник
k := k / j;
делаетСлегка измененная версия в C #, которая дает необходимые перестановки в массиве ЛЮБОГО типа.
источник
Permutations(vals).ToArray()
то получите N ссылок на один и тот же массив. Если вы хотите сохранить результаты, вы должны вручную создать копию. НапримерPermutations(values).Select(v => (T[])v.Clone())
источник
Мне понравился подход FBryant87, поскольку он прост. К сожалению, он, как и многие другие «решения», не предлагает все перестановки или, например, целое число, если он содержит одну и ту же цифру более одного раза. Возьмите 656123 в качестве примера. Линия:
используя Кроме причинит все случаи должны быть удалены, то есть , когда с = 6, две цифры удаляются , и мы остались с , например , 5123. Поскольку ни один из решений я пытался решить это, я решил попробовать и решить сам по FBryant87 «с код в качестве базы. Вот что я придумал:
Я просто удаляю первое найденное вхождение, используя .Remove и .IndexOf. Кажется, работает как предназначено для моего использования по крайней мере. Я уверен, что это можно сделать умнее.
Однако следует отметить одну вещь: результирующий список может содержать дубликаты, поэтому убедитесь, что вы либо заставили метод вернуть, например, HashSet, либо удалили дубликаты после возврата, используя любой понравившийся метод.
источник
Вот хорошая статья, охватывающая три алгоритма для нахождения всех перестановок, в том числе один для нахождения следующей перестановки.
http://www.cut-the-knot.org/do_you_know/AllPerm.shtml
C ++ и Python имеют встроенные функции next_permutation и itertools.permutations соответственно.
источник
Вот чисто функциональная реализация F #:
Производительность может быть значительно улучшена путем изменения подкачки, чтобы воспользоваться изменчивой природой массивов CLR, но эта реализация является поточно-ориентированной по отношению к исходному массиву, и это может быть желательно в некоторых контекстах. Кроме того, для массивов с более чем 16 элементами int необходимо заменить на типы с большей / произвольной точностью, поскольку факториал 17 приводит к переполнению int32.
источник
Вот простое решение в C # с использованием рекурсии,
источник
Вот простая для понимания функция перестановки для строки и целого числа в качестве входных данных. При этом вы даже можете установить свою выходную длину (которая в нормальном случае равна длине ввода)
строка
а для Integer просто измените метод вызывающей стороны, и MakePermutations () останется нетронутым:
пример 1: GetAllPermutations ("abc", 3); "abc" "acb" "bac" "bca" "cab" "cba"
пример 2: GetAllPermutations ("abcd", 2); "ab" "ac" "ad" "ba" "bc" "bd" "ca" "cb" "cd" "da" "db" "dc"
пример 3: GetAllPermutations (486,2); 48 46 84 86 64 68
источник
Вот функция, которая будет печатать все перестановки. Эта функция реализует логику, объясненную Петром.
источник
Ниже моя реализация перестановки. Не обращайте внимания на имена переменных, так как я делал это для удовольствия :)
источник
Вот пример высокого уровня, который я написал, который иллюстрирует объяснение на человеческом языке, которое дал Питер:
источник
Если производительность и память являются проблемой, я предлагаю эту очень эффективную реализацию. Согласно алгоритму Хипа в Википедии , он должен быть самым быстрым. Надеюсь, что это будет соответствовать вашим потребностям :-)!
Так же, как сравнение этого с реализацией Linq для 10! (код включен):
Linq: 36288000 наименований в 50051 миллисек
источник
Вот мое решение в JavaScript (NodeJS). Основная идея заключается в том, что мы берем один элемент за раз, «удаляем его» из строки, меняем остальные символы и вставляем элемент впереди.
А вот и тесты:
источник
Вот самое простое решение, которое я могу придумать:
distribute
Функция принимает новый элементe
иn
-элементный список и возвращает списокn+1
списков , каждый из которых имеетe
вставленные в другом месте. Например, вставляя10
в каждое из четырех возможных мест в списке[1;2;3]
:permute
Функция складки над каждым элементом в своей очереди , распределяющий над перестановками , накопленных до сих пор, кульминация всех перестановок. Например, 6 перестановок в списке[1;2;3]
:Изменение на
fold
ascan
для сохранения промежуточных аккумуляторов проливает некоторый свет на то, как перестановки генерируются элементом за раз:источник
Перечисляет перестановки строки. Избегает дублирования при повторении символов:
источник
Основываясь на решении @ Peter, вот версия, которая объявляет простой
Permutations()
метод расширения в стиле LINQ, который работает на любомIEnumerable<T>
.Использование (на примере строковых символов):
Выходы:
Или на любой другой тип коллекции:
Выходы:
источник
Вот функция, которая будет печатать все перестановки рекурсивно.
источник
источник
Вот ответ C #, который немного упрощен.
Вывод:
источник
Это мое решение, которое мне легко понять
источник
Вот еще одна реализация упомянутого алгоритма.
источник
new Permutation().GenerateFor("aba")
выходыstring[4] { "ab", "baa", "baa", "ab" }
источник
источник