I am struggling with generating circular permutations, or solving the "Necklace Problem" with Python. I am basically looking to generate all circular permutations of a list as efficiently as possible.
Basically, assume we have a list [1,2,3,4], I want to generate all unique permutations in a circular fashion. So:
[1,2,3,4], [1,3,2,4]
Would be considered different, whereas:
[1,2,3,4], [4,1,2,3] would be considered the same, as I am looking only for unique permutations of a circular list.
I have tried generating all permutations with itertools
but this is very inefficient when using larger length lists.
As another example, consider a running loop songs, characterised by [1,2,3,4,5] playing on repeat. I am trying to come up with an algorithm to generate only unique orders. Obviously [1,2,3,4,5] and [4,5,1,2,3] would result in the same order.
Struggling and would appreciate some help to solve this problem!
When you havea list of N elements, one of the circular permutations of the list is uniquely given by its first element. Than means that you will have exactly N circular permutation (including the original list), and you can pass from one to another by removing fist element and adding it at the end of the list.
You can easily build a generator for all the circular permutations of a list:
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
Demo:
>>> list(circ_perm([1,2,3,4]))
[[1, 2, 3, 4], [2, 3, 4, 1], [3, 4, 1, 2], [4, 1, 2, 3]]
If what you want is the unique permutations when two permutations that are a ciruclar permution of the other one, you can still use the fact that a circular permutation is given by its first element and fix the first element and find all the permutations of what remains:
def uniq_perm(lst):
gen = itertools.permutations(lst[1:])
for end in gen:
yield [lst[0]] + list(end)
Demo:
>>> 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]]
The complexity for making permutation is about O(n*n!), so for large number or list it would inefficient to generate all possible permutations, You can use backtracking to generating list permutation, I'll share a link may be this would help. The solution is based on the backtracking
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)
The following code produces all permutations of the last n-1
numbers, prepending each permutation with the first element of the original list.
from itertools import permutations
circular_perms = [my_list[:1]+list(perm) for perm in permutations(my_list[1:])]
Where my_list
is your initial list of values to generation all circular permutations of.
Because the itertool.permutations generator in Python has the first item in the input list varying the least in successive output, the following code just outputs all the solutions as seen when rotated to the fixed point above.
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)]
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.