Алгоритмы Python: генерация ожерелья / круговые перестановки

Я борюсь с генерацией круговых перестановок или решением «проблемы ожерелья» с помощью 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?

Ashish Acharya 26.07.2018 08:04

Можете поделиться тем, что пробовали в itertools? А о какой длине элементов идет речь в вашем случае? Itertools в целом можно рассматривать как довольно эффективную реализацию большинства вещей ...

dennlinger 26.07.2018 08:04

Проблема в том, что я не собираюсь генерировать все перестановки, поэтому использование чего-то вроде perms = itertools.permutations(my_list) неэффективно. Я хочу генерировать только уникальные перестановки в круговом массиве.

Joe 26.07.2018 08:15
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
3
4 549
5

Ответы 5

Когда у вас есть список из 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]]

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

Joe 26.07.2018 08:24

Итак, я ищу вывод, такой как [1,3,2,4], из ввода [1,2,3,4]

Joe 26.07.2018 08:25

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

Joe 26.07.2018 08:27

@joe: 4 !. Сгенерируйте все перестановки, которые начинаются с 1 (т. Е. Сгенерируйте все перестановки последних элементов n-1). Никакие два из них не являются вращениями друг друга, потому что все они имеют 1 в одном и том же месте. Я подозреваю, что ваша настоящая цель иная.

rici 26.07.2018 09:22

Сложность выполнения перестановки составляет около 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]. Я ищу только уникальные заказы вокруг кругового массива. Таким образом, никакие два элемента не должны появляться рядом друг с другом дважды.

Joe 26.07.2018 08:42

Следующий код производит все перестановки последних чисел n-1, добавляя к каждой перестановке первый элемент исходного списка.

from itertools import permutations
circular_perms = [my_list[:1]+list(perm) for perm in permutations(my_list[1:])]

Где my_list - ваш начальный список значений для генерации всех циклических перестановок.

  1. Подумайте о «неподвижной точке» ожерелья.
  2. позаботьтесь о том, чтобы бусинка с наименьшим номером, 1, была повернута в эту точку
  3. Тогда только заказы бисера это все перестановки элементов, начинающиеся с 1

Поскольку генератор 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)) вместо подвыражения деления //.

Paddy3118 27.07.2018 00:37

Есть две библиотеки Python (о которых я знаю), которые будут генерировать комбинаторные ожерелья. Это мудрец и SymPy.

Другие вопросы по теме