Я борюсь с генерацией круговых перестановок или решением «проблемы ожерелья» с помощью Python. Я в основном пытаюсь максимально эффективно сгенерировать все круговые перестановки списка.
В принципе, предположим, что у нас есть список [1,2,3,4], я хочу генерировать все уникальные перестановки по кругу. Так:
[1,2,3,4], [1,3,2,4]
Будет считаться другим, тогда как:
[1,2,3,4], [4,1,2,3] будут считаться одинаковыми, поскольку я ищу только уникальные перестановки кругового списка.
Я пробовал сгенерировать все перестановки с помощью itertools, но это очень неэффективно при использовании списков большей длины.
В качестве другого примера рассмотрим песни с бегущей петлей, для которых [1,2,3,4,5] воспроизводятся с повторением. Я пытаюсь придумать алгоритм для создания только уникальных заказов. Очевидно, что [1,2,3,4,5] и [4,5,1,2,3] будут иметь одинаковый порядок.
Боритесь, и был бы признателен за помощь в решении этой проблемы!
Можете поделиться тем, что пробовали в itertools? А о какой длине элементов идет речь в вашем случае? Itertools в целом можно рассматривать как довольно эффективную реализацию большинства вещей ...
Проблема в том, что я не собираюсь генерировать все перестановки, поэтому использование чего-то вроде perms = itertools.permutations(my_list) неэффективно. Я хочу генерировать только уникальные перестановки в круговом массиве.






Когда у вас есть список из N элементов, одна из циклических перестановок списка однозначно задается его первым элементом. Это означает, что у вас будет ровно N циклических перестановок (включая исходный список), и вы можете переходить от одного к другому, удаляя первый элемент и добавляя его в конец списка.
Вы можете легко создать генератор для всех циклических перестановок списка:
def circ_perm(lst):
cpy = lst[:] # take a copy because a list is a mutable object
yield cpy
for i in range(len(lst) - 1):
cpy = cpy[1:] + [cpy[0]]
yield cpy
Демо:
>>> list(circ_perm([1,2,3,4]))
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
Если вам нужны уникальные перестановки, когда две перестановки являются круговой перестановкой другого, вы все равно можете использовать тот факт, что круговая перестановка задается его первым элементом, и исправить первый элемент и найти все перестановки того, что осталось. :
def uniq_perm(lst):
gen = itertools.permutations(lst[1:])
for end in gen:
yield [lst[0]] + list(end)
Демо:
>>> list(uniq_perm([1,2,3,4]))
[[1, 2, 3, 4], [1, 2, 4, 3], [1, 3, 2, 4], [1, 3, 4, 2], [1, 4, 2, 3], [1, 4, 3, 2]]
Я действительно хочу создать уникальные перестановки в круговом списке. Результат вашего метода дает те, которые мне нужно было бы исключить.
Итак, я ищу вывод, такой как [1,3,2,4], из ввода [1,2,3,4]
Так что в основном проблема "ожерелья". Предположим, у вас есть 5 уникальных бусин на ожерелье, сколько разных порядков бусинок у вас может быть, независимо от того, поворачивается ли ожерелье?
@joe: 4 !. Сгенерируйте все перестановки, которые начинаются с 1 (т. Е. Сгенерируйте все перестановки последних элементов n-1). Никакие два из них не являются вращениями друг друга, потому что все они имеют 1 в одном и том же месте. Я подозреваю, что ваша настоящая цель иная.
Сложность выполнения перестановки составляет около O (n * n!), Поэтому для большого числа или списка было бы неэффективно генерировать все возможные перестановки. Вы можете использовать отслеживание с возвратом для создания перестановки списка, я поделюсь ссылкой, может быть, это поможет . Решение основано на возврате
def permute(a, l, r):
if l == r:
print(a)
else:
for i in range(l, r + 1):
a[l], a[i] = a[i], a[l]
permute(a, l + 1, r)
a[l], a[i] = a[i], a[l]
data = [1,2,3,4,5]
n = len(data)
a = list(data)
permute(a, 0, n - 1)Спасибо, похоже, это вычисляет все перестановки, поэтому генерируется [1,2,3,4,5], но также, например, [5,4,3,2,1]. Я ищу только уникальные заказы вокруг кругового массива. Таким образом, никакие два элемента не должны появляться рядом друг с другом дважды.
Следующий код производит все перестановки последних чисел n-1, добавляя к каждой перестановке первый элемент исходного списка.
from itertools import permutations
circular_perms = [my_list[:1]+list(perm) for perm in permutations(my_list[1:])]
Где my_list - ваш начальный список значений для генерации всех циклических перестановок.
Поскольку генератор itertool.permutations в Python имеет первый элемент во входном списке, наименее изменяющийся при последовательном выходе, следующий код просто выводит все решения, как видно при повороте на фиксированную точку выше.
from itertools import permutations, islice
from math import factorial
items = [1, 2, 3 ,4]
ilength = len(items)
base_necklace_orders = list(islice(permutations(items), factorial(ilength) // ilength))
print(base_necklace_orders)
# [(1, 2, 3, 4), (1, 2, 4, 3), (1, 3, 2, 4), (1, 3, 4, 2), (1, 4, 2, 3), (1, 4, 3, 2)]Я мог бы использовать int(factorial(ilength - 1)) вместо подвыражения деления //.
вы можете показать нам код, который вы написали с помощью
itertools?