Як генерувати всі перестановки списку?


592

Як ви генеруєте всі перестановки списку в Python, незалежно від типу елементів у цьому списку?

Наприклад:

permutations([])
[]

permutations([1])
[1]

permutations([1, 2])
[1, 2]
[2, 1]

permutations([1, 2, 3])
[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]

5
Я згоден з рекурсивною, прийнятою відповіддю - СЬОГОДНІ. Однак це все ще залишається величезною проблемою інформатики. Прийнята відповідь вирішує цю проблему з експоненціальною складністю (2 ^ NN = len (список)) Вирішіть її (або доведіть, що не можете) в поліноміальний час :) Див. "Проблема продавця подорожей"
FlipMcF

37
@FlipMcF Це буде важко "вирішити" в поліномічний час, враховуючи, що потрібен факторний час, щоб навіть просто перерахувати вихід ... так, ні, це неможливо.
Томас

Відповіді:


488

Починаючи з Python 2.6 (і якщо ви на Python 3) у вас є стандартна бібліотека інструмент для цього: itertools.permutations.

import itertools
list(itertools.permutations([1, 2, 3]))

Якщо ви використовуєте старіший Python (<2.6) з якихось причин або просто цікаво дізнатися, як це працює, ось один приємний підхід, взятий з http://code.activestate.com/recipes/252178/ :

def all_perms(elements):
    if len(elements) <=1:
        yield elements
    else:
        for perm in all_perms(elements[1:]):
            for i in range(len(elements)):
                # nb elements[0:1] works in both string and list contexts
                yield perm[:i] + elements[0:1] + perm[i:]

Кілька альтернативних підходів перераховані в документації до itertools.permutations. Ось один:

def permutations(iterable, r=None):
    # permutations('ABCD', 2) --> AB AC AD BA BC BD CA CB CD DA DB DC
    # permutations(range(3)) --> 012 021 102 120 201 210
    pool = tuple(iterable)
    n = len(pool)
    r = n if r is None else r
    if r > n:
        return
    indices = range(n)
    cycles = range(n, n-r, -1)
    yield tuple(pool[i] for i in indices[:r])
    while n:
        for i in reversed(range(r)):
            cycles[i] -= 1
            if cycles[i] == 0:
                indices[i:] = indices[i+1:] + indices[i:i+1]
                cycles[i] = n - i
            else:
                j = cycles[i]
                indices[i], indices[-j] = indices[-j], indices[i]
                yield tuple(pool[i] for i in indices[:r])
                break
        else:
            return

І ще одна, заснована на itertools.product:

def permutations(iterable, r=None):
    pool = tuple(iterable)
    n = len(pool)
    r = n if r is None else r
    for indices in product(range(n), repeat=r):
        if len(set(indices)) == r:
            yield tuple(pool[i] for i in indices)

14
Це та інші рекурсивні рішення можуть мати небезпеку з'їсти всю оперативну пам’ять, якщо перестановлений список буде досить великим
Борис Горелик,

3
Вони також досягають межі рекурсії (і вмирають) з великими списками
вбр

58
bgbg, dbr: його використовується генератор, тому сама функція не з'їдає пам'ять. Залишається вам про те, як споживати ітератор, повернутий all_perms (скажімо, ви можете записати кожну ітерацію на диск і не турбуватися про пам'ять). Я знаю, що ця публікація стара, але я пишу це на благо всіх, хто зараз її читає. Також зараз найкращим способом було б використання itertools.permutations (), на що вказують багато хто.
Ягтеш Чадха

18
Не тільки генератор. Він використовує вкладені генератори, які поступаються попередньому до стека викликів, якщо це не зрозуміло. Він використовує O (n) пам'ять, що добре.
cdunn2001

1
PS: Я виправив це, for i in range(len(elements))замість цього for i in range(len(elements)+1). Насправді виділений елемент elements[0:1]може знаходитися в len(elements)різних положеннях, в результаті - ні len(elements)+1.
Ерік О Лебіго

339

А в Python 2.6 далі:

import itertools
itertools.permutations([1,2,3])

(повернуто як генератор. Використовуйте list(permutations(l))для повернення як список.)


15
Працює і в Python 3
Wheleph,

10
Зауважте, що існує rпараметр, наприклад itertools.permutations([1,2,3], r=2), який генерує всі можливі перестановки, вибираючи 2 елементи:[(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)]
toto_tico

277

Наступний код із Питоном 2.6 та вище ТІЛЬКИ

По-перше, імпортуйте itertools:

import itertools

Перестановка (питання порядку):

print list(itertools.permutations([1,2,3,4], 2))
[(1, 2), (1, 3), (1, 4),
(2, 1), (2, 3), (2, 4),
(3, 1), (3, 2), (3, 4),
(4, 1), (4, 2), (4, 3)]

Поєднання (замовлення НЕ має значення):

print list(itertools.combinations('123', 2))
[('1', '2'), ('1', '3'), ('2', '3')]

Декартовий продукт (з кількома ітерабелями):

print list(itertools.product([1,2,3], [4,5,6]))
[(1, 4), (1, 5), (1, 6),
(2, 4), (2, 5), (2, 6),
(3, 4), (3, 5), (3, 6)]

Декартовий продукт (з одним ітерабельним і самим):

print list(itertools.product([1,2], repeat=3))
[(1, 1, 1), (1, 1, 2), (1, 2, 1), (1, 2, 2),
(2, 1, 1), (2, 1, 2), (2, 2, 1), (2, 2, 2)]


`список друку (itertools.permutations ([1,2,3,4], 2)) ^` SyntaxError: неправильний синтаксис` Тільки починаючи використовувати код VS Що я зробив неправильно? Вказівник вказує під "t" "списку"
gus

39
def permutations(head, tail=''):
    if len(head) == 0: print tail
    else:
        for i in range(len(head)):
            permutations(head[0:i] + head[i+1:], tail+head[i])

називається:

permutations('abc')

Навіщо друкувати хвіст, а потім повертати None? Чому б замість цього не повернути хвіст? Чому б взагалі нічого не повернути?
bugmenot123

30
#!/usr/bin/env python

def perm(a, k=0):
   if k == len(a):
      print a
   else:
      for i in xrange(k, len(a)):
         a[k], a[i] = a[i] ,a[k]
         perm(a, k+1)
         a[k], a[i] = a[i], a[k]

perm([1,2,3])

Вихід:

[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 2, 1]
[3, 1, 2]

Оскільки я змінюю вміст списку, для введення даних потрібен тип послідовності, що змінюється Напр. perm(list("ball"))Буде працювати, але perm("ball")не буде, тому що ви не можете змінити рядок.

Ця реалізація Python натхненна алгоритмом, представленим у книзі Комп'ютерні алгоритми Горовіца, Сані та Раджасекерана .


Я припускаю, що k - довжина або перестановки. Для k = 2 виходи [1, 2, 3]. Чи не повинно бути (1, 2) (1, 3) (2, 1) (2, 3) (3, 1) (3, 2) ??
Костянтинос Монахопулос

k - індекс елемента, на який потрібно поміняти
місцями

22

Це рішення реалізує генератор, щоб утримувати всі перестановки в пам'яті:

def permutations (orig_list):
    if not isinstance(orig_list, list):
        orig_list = list(orig_list)

    yield orig_list

    if len(orig_list) == 1:
        return

    for n in sorted(orig_list):
        new_list = orig_list[:]
        pos = new_list.index(n)
        del(new_list[pos])
        new_list.insert(0, n)
        for resto in permutations(new_list[1:]):
            if new_list[:1] + resto <> orig_list:
                yield new_list[:1] + resto

16

У функціональному стилі

def addperm(x,l):
    return [ l[0:i] + [x] + l[i:]  for i in range(len(l)+1) ]

def perm(l):
    if len(l) == 0:
        return [[]]
    return [x for y in perm(l[1:]) for x in addperm(l[0],y) ]

print perm([ i for i in range(3)])

Результат:

[[0, 1, 2], [1, 0, 2], [1, 2, 0], [0, 2, 1], [2, 0, 1], [2, 1, 0]]

15

Наступний код - це місцева перестановка даного списку, реалізована як генератор. Оскільки він повертає лише посилання на список, список не повинен бути змінений поза генератором. Рішення нерекурсивне, тому використовує мало пам'яті. Також добре працюйте з кількома копіями елементів у списку вводу.

def permute_in_place(a):
    a.sort()
    yield list(a)

    if len(a) <= 1:
        return

    first = 0
    last = len(a)
    while 1:
        i = last - 1

        while 1:
            i = i - 1
            if a[i] < a[i+1]:
                j = last - 1
                while not (a[i] < a[j]):
                    j = j - 1
                a[i], a[j] = a[j], a[i] # swap the values
                r = a[i+1:last]
                r.reverse()
                a[i+1:last] = r
                yield list(a)
                break
            if i == first:
                a.reverse()
                return

if __name__ == '__main__':
    for n in range(5):
        for a in permute_in_place(range(1, n+1)):
            print a
        print

    for a in permute_in_place([0, 0, 1, 1, 1]):
        print a
    print

15

На мою думку, цілком очевидним способом може бути також:

def permutList(l):
    if not l:
            return [[]]
    res = []
    for e in l:
            temp = l[:]
            temp.remove(e)
            res.extend([[e] + r for r in permutList(temp)])

    return res

11
list2Perm = [1, 2.0, 'three']
listPerm = [[a, b, c]
            for a in list2Perm
            for b in list2Perm
            for c in list2Perm
            if ( a != b and b != c and a != c )
            ]
print listPerm

Вихід:

[
    [1, 2.0, 'three'], 
    [1, 'three', 2.0], 
    [2.0, 1, 'three'], 
    [2.0, 'three', 1], 
    ['three', 1, 2.0], 
    ['three', 2.0, 1]
]

2
Хоча технічно це дає бажаний вихід, ви вирішуєте щось, що може бути O (n lg n) в O (n ^ n) - "трохи" неефективним для великих наборів.
Джеймс

3
@James: Мене трохи бентежить O (n log n), який ви даєте: кількість перестановок n !, що вже набагато більше, ніж O (n log n); тож я не бачу, яким рішенням може бути O (n log n). Однак вірно, що це рішення знаходиться в O (n ^ n), що набагато більше n !, як видно з наближення Стірлінга.
Ерік О Лебігот

9

Я використовував алгоритм, заснований на системі фактичних чисел. Для списку довжини n ви можете збирати кожен елемент перестановки за пунктом, вибираючи з елементів, залишених на кожному етапі. Ви маєте n варіантів для першого елемента, n-1 для другого, і лише один для останнього, тому ви можете використовувати цифри числа в системі фактичних чисел як індекси. Таким чином числа від 0 до n! -1 відповідають усім можливим перестановкам у лексикографічному порядку.

from math import factorial
def permutations(l):
    permutations=[]
    length=len(l)
    for x in xrange(factorial(length)):
        available=list(l)
        newPermutation=[]
        for radix in xrange(length, 0, -1):
            placeValue=factorial(radix-1)
            index=x/placeValue
            newPermutation.append(available.pop(index))
            x-=index*placeValue
        permutations.append(newPermutation)
    return permutations

permutations(range(3))

вихід:

[[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]]

Цей метод є нерекурсивним, але він трохи повільніше на моєму комп’ютері і xrange викликає помилку, коли n! занадто великий, щоб перетворити його на ціле ціле C (для мене n = 13). Було достатньо, коли мені це було потрібно, але це не itertools.permutations довгого пострілу.


3
Привіт, Ласкаво просимо до Stack Overflow. Хоча розміщення методу грубої сили має свої переваги, якщо ви не вважаєте, що ваше рішення краще, ніж прийняте рішення, ви, ймовірно, не повинні його публікувати (особливо на старе питання, на яке вже так багато відповідей).
Ганнеле

1
Я насправді шукав жорстокий небібліотечний підхід, тож дякую!
Джей Тейлор

8

Зауважимо, що цей алгоритм має n factorialчасову складність, де nдовжина вхідного списку

Роздрукуйте результати:

global result
result = [] 

def permutation(li):
if li == [] or li == None:
    return

if len(li) == 1:
    result.append(li[0])
    print result
    result.pop()
    return

for i in range(0,len(li)):
    result.append(li[i])
    permutation(li[:i] + li[i+1:])
    result.pop()    

Приклад:

permutation([1,2,3])

Вихід:

[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 1, 2]
[3, 2, 1]

8

Дійсно можна повторити перший елемент кожної перестановки, як у відповіді tzwenn. Однак ефективніше написати це рішення так:

def all_perms(elements):
    if len(elements) <= 1:
        yield elements  # Only permutation possible = no permutation
    else:
        # Iteration over the first element in the result permutation:
        for (index, first_elmt) in enumerate(elements):
            other_elmts = elements[:index]+elements[index+1:]
            for permutation in all_perms(other_elmts): 
                yield [first_elmt] + permutation

Це рішення приблизно на 30% швидше, мабуть, завдяки рекурсії, що закінчується len(elements) <= 1замість 0. Він також набагато ефективніший у пам'яті, оскільки він використовує функцію генератора (наскрізь yield), як у рішенні Ріккардо Рейєса.


6

На це надихає реалізація Haskell, використовуючи розуміння списку:

def permutation(list):
    if len(list) == 0:
        return [[]]
    else:
        return [[x] + ys for x in list for ys in permutation(delete(list, x))]

def delete(list, item):
    lc = list[:]
    lc.remove(item)
    return lc

6

Регулярна реалізація (без урожайності - зробить все на пам’ять):

def getPermutations(array):
    if len(array) == 1:
        return [array]
    permutations = []
    for i in range(len(array)): 
        # get all perm's of subarray w/o current item
        perms = getPermutations(array[:i] + array[i+1:])  
        for p in perms:
            permutations.append([array[i], *p])
    return permutations

Реалізація виходу:

def getPermutations(array):
    if len(array) == 1:
        yield array
    else:
        for i in range(len(array)):
            perms = getPermutations(array[:i] + array[i+1:])
            for p in perms:
                yield [array[i], *p]

Основна ідея - перейти всі елементи в масиві для 1-ї позиції, а потім у 2-й позиції перейти всі решта елементів без обраного елемента для 1-го і т. Д. Це можна зробити за допомогою рекурсії , де Критеріями зупинки стає потрапляння до масиву з 1 елемента - у цьому випадку ви повертаєте цей масив.

введіть тут опис зображення


Для мене це не працює _> ValueError: операнди не вдалося транслювати разом із фігурами (0,) (2,) для цього рядка:perms = getPermutations(array[:i] + array[i+1:])
RK1

@ RK1 який був вхід?
Девід Рефаелі

Я проходжу в numpyмасиві _> getPermutations(np.array([1, 2, 3])), я бачу, що він працює для списку, просто заплутався, як аргумент func array:)
RK1

@ RK1 радий, що він працює :-) список - це ключове слово в python, тому зазвичай не годиться називати свій параметр ключовим словом, оскільки це "затінить" його. Тому я використовую слово масив, оскільки це фактична функціональність списку, який я використовую, - їх масив, як спосіб. Я думаю, якби я написав документацію, я б уточнив її. Також я вважаю, що основні питання "інтерв'ю" повинні вирішуватися без зовнішніх пакетів, як, наприклад, нуміз.
Девід Рефаелі

Ха-ха, це правда, так, намагався використати його numbaта отримав жадібність зі швидкістю, тому намагався використовувати його виключно з numpyмасивами
RK1

4

Для продуктивності, нудне рішення, натхнене Кнутом , (p22):

from numpy import empty, uint8
from math import factorial

def perms(n):
    f = 1
    p = empty((2*n-1, factorial(n)), uint8)
    for i in range(n):
        p[i, :f] = i
        p[i+1:2*i+1, :f] = p[:i, :f]  # constitution de blocs
        for j in range(i):
            p[:i+1, f*(j+1):f*(j+2)] = p[j+1:j+i+2, :f]  # copie de blocs
        f = f*(i+1)
    return p[:n, :]

Копіювання великих блоків пам'яті економить час - це в 20 разів швидше, ніж list(itertools.permutations(range(n)):

In [1]: %timeit -n10 list(permutations(range(10)))
10 loops, best of 3: 815 ms per loop

In [2]: %timeit -n100 perms(10) 
100 loops, best of 3: 40 ms per loop

3
from __future__ import print_function

def perm(n):
    p = []
    for i in range(0,n+1):
        p.append(i)
    while True:
        for i in range(1,n+1):
            print(p[i], end=' ')
        print("")
        i = n - 1
        found = 0
        while (not found and i>0):
            if p[i]<p[i+1]:
                found = 1
            else:
                i = i - 1
        k = n
        while p[i]>p[k]:
            k = k - 1
        aux = p[i]
        p[i] = p[k]
        p[k] = aux
        for j in range(1,(n-i)/2+1):
            aux = p[i+j]
            p[i+j] = p[n-j+1]
            p[n-j+1] = aux
        if not found:
            break

perm(5)

3

Ось алгоритм, який працює над списком без створення нових проміжних списків, подібних до рішення Бер, за посиланням https://stackoverflow.com/a/108651/184528 .

def permute(xs, low=0):
    if low + 1 >= len(xs):
        yield xs
    else:
        for p in permute(xs, low + 1):
            yield p        
        for i in range(low + 1, len(xs)):        
            xs[low], xs[i] = xs[i], xs[low]
            for p in permute(xs, low + 1):
                yield p        
            xs[low], xs[i] = xs[i], xs[low]

for p in permute([1, 2, 3, 4]):
    print p

Ви можете спробувати код для себе тут: http://repl.it/J9v


3

Краса рекурсії:

>>> import copy
>>> def perm(prefix,rest):
...      for e in rest:
...              new_rest=copy.copy(rest)
...              new_prefix=copy.copy(prefix)
...              new_prefix.append(e)
...              new_rest.remove(e)
...              if len(new_rest) == 0:
...                      print new_prefix + new_rest
...                      continue
...              perm(new_prefix,new_rest)
... 
>>> perm([],['a','b','c','d'])
['a', 'b', 'c', 'd']
['a', 'b', 'd', 'c']
['a', 'c', 'b', 'd']
['a', 'c', 'd', 'b']
['a', 'd', 'b', 'c']
['a', 'd', 'c', 'b']
['b', 'a', 'c', 'd']
['b', 'a', 'd', 'c']
['b', 'c', 'a', 'd']
['b', 'c', 'd', 'a']
['b', 'd', 'a', 'c']
['b', 'd', 'c', 'a']
['c', 'a', 'b', 'd']
['c', 'a', 'd', 'b']
['c', 'b', 'a', 'd']
['c', 'b', 'd', 'a']
['c', 'd', 'a', 'b']
['c', 'd', 'b', 'a']
['d', 'a', 'b', 'c']
['d', 'a', 'c', 'b']
['d', 'b', 'a', 'c']
['d', 'b', 'c', 'a']
['d', 'c', 'a', 'b']
['d', 'c', 'b', 'a']

3

Цей алгоритм є найефективнішим, він дозволяє уникнути проходження масиву та маніпулювання рекурсивними викликами, працює в Python 2, 3:

def permute(items):
    length = len(items)
    def inner(ix=[]):
        do_yield = len(ix) == length - 1
        for i in range(0, length):
            if i in ix: #avoid duplicates
                continue
            if do_yield:
                yield tuple([items[y] for y in ix + [i]])
            else:
                for p in inner(ix + [i]):
                    yield p
    return inner()

Використання:

for p in permute((1,2,3)):
    print(p)

(1, 2, 3)
(1, 3, 2)
(2, 1, 3)
(2, 3, 1)
(3, 1, 2)
(3, 2, 1)

3
def pzip(c, seq):
    result = []
    for item in seq:
        for i in range(len(item)+1):
            result.append(item[i:]+c+item[:i])
    return result


def perm(line):
    seq = [c for c in line]
    if len(seq) <=1 :
        return seq
    else:
        return pzip(seq[0], perm(seq[1:]))

3

ІНШИЙ ПІДХІД (без губ)

def permutation(input):
    if len(input) == 1:
        return input if isinstance(input, list) else [input]

    result = []
    for i in range(len(input)):
        first = input[i]
        rest = input[:i] + input[i + 1:]
        rest_permutation = permutation(rest)
        for p in rest_permutation:
            result.append(first + p)
    return result

Введенням може бути рядок або список

print(permutation('abcd'))
print(permutation(['a', 'b', 'c', 'd']))

Це не працює для списку з цілими числами, наприклад. [1, 2, 3]повернення[6, 6, 6, 6, 6, 6]
RK1

@ RK1, ти можеш спробувати цеprint(permutation(['1','2','3']))
Tatsu

Завдяки цьому працює
RK1

3

Відмова від відповідальності: безформний штепсель від автора пакета. :)

Пакет " trotter" відрізняється від більшості реалізацій тим, що він генерує псевдо списки, які насправді не містять перестановок, а описують відображення між перестановками та відповідними позиціями в наказі, що дозволяє працювати з дуже великими "списками" перестановок, як показано у цій демонстрації яка виконує досить миттєві операції та перегляди в псевдо-списку ", що містить" усі перестановки літер в алфавіті, не використовуючи більше пам'яті та обробки, ніж звичайна веб-сторінка.

У будь-якому випадку, щоб створити список перестановок, ми можемо зробити наступне.

import trotter

my_permutations = trotter.Permutations(3, [1, 2, 3])

print(my_permutations)

for p in my_permutations:
    print(p)

Вихід:

Псевдо-список, що містить 6 3-перестановок [1, 2, 3].
[1, 2, 3]
[1, 3, 2]
[3, 1, 2]
[3, 2, 1]
[2, 3, 1]
[2, 1, 3]

2

Створення всіх можливих перестановок

Я використовую python3.4:

def calcperm(arr, size):
    result = set([()])
    for dummy_idx in range(size):
        temp = set()
        for dummy_lst in result:
            for dummy_outcome in arr:
                if dummy_outcome not in dummy_lst:
                    new_seq = list(dummy_lst)
                    new_seq.append(dummy_outcome)
                    temp.add(tuple(new_seq))
        result = temp
    return result

Випробування:

lst = [1, 2, 3, 4]
#lst = ["yellow", "magenta", "white", "blue"]
seq = 2
final = calcperm(lst, seq)
print(len(final))
print(final)

2

Щоб заощадити людям можливі години пошуку та експериментів, ось нерекурсивне рішення перестановок у Python, яке також працює з Numba (з версії 0.41):

@numba.njit()
def permutations(A, k):
    r = [[i for i in range(0)]]
    for i in range(k):
        r = [[a] + b for a in A for b in r if (a in b)==False]
    return r
permutations([1,2,3],3)
[[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]

Щоб скласти враження про продуктивність:

%timeit permutations(np.arange(5),5)

243 µs ± 11.1 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)
time: 406 ms

%timeit list(itertools.permutations(np.arange(5),5))
15.9 µs ± 8.61 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
time: 12.9 s

Тому використовуйте цю версію, лише якщо вам потрібно викликати її з функції njitted, інакше віддайте перевагу реалізації itertools.


1

Я бачу, що в цих рекурсивних функціях відбувається багато ітерацій, не зовсім чиста рекурсія ...

тож для тих із вас, хто не може дотриматись жодної петлі, ось вагоме, абсолютно непотрібне повністю рекурсивне рішення

def all_insert(x, e, i=0):
    return [x[0:i]+[e]+x[i:]] + all_insert(x,e,i+1) if i<len(x)+1 else []

def for_each(X, e):
    return all_insert(X[0], e) + for_each(X[1:],e) if X else []

def permute(x):
    return [x] if len(x) < 2 else for_each( permute(x[1:]) , x[0])


perms = permute([1,2,3])

1

Ще одне рішення:

def permutation(flag, k =1 ):
    N = len(flag)
    for i in xrange(0, N):
        if flag[i] != 0:
            continue
        flag[i] = k 
        if k == N:
            print flag
        permutation(flag, k+1)
        flag[i] = 0

permutation([0, 0, 0])

0

Моє рішення Python:

def permutes(input,offset):
    if( len(input) == offset ):
        return [''.join(input)]

    result=[]        
    for i in range( offset, len(input) ):
         input[offset], input[i] = input[i], input[offset]
         result = result + permutes(input,offset+1)
         input[offset], input[i] = input[i], input[offset]
    return result

# input is a "string"
# return value is a list of strings
def permutations(input):
    return permutes( list(input), 0 )

# Main Program
print( permutations("wxyz") )

0
def permutation(word, first_char=None):
    if word == None or len(word) == 0: return []
    if len(word) == 1: return [word]

    result = []
    first_char = word[0]
    for sub_word in permutation(word[1:], first_char):
        result += insert(first_char, sub_word)
    return sorted(result)

def insert(ch, sub_word):
    arr = [ch + sub_word]
    for i in range(len(sub_word)):
        arr.append(sub_word[i:] + ch + sub_word[:i])
    return arr


assert permutation(None) == []
assert permutation('') == []
assert permutation('1')  == ['1']
assert permutation('12') == ['12', '21']

print permutation('abc')

Вихід: ['abc', 'acb', 'bac', 'bca', 'cab', 'cba']


0

Використання Counter

from collections import Counter

def permutations(nums):
    ans = [[]]
    cache = Counter(nums)

    for idx, x in enumerate(nums):
        result = []
        for items in ans:
            cache1 = Counter(items)
            for id, n in enumerate(nums):
                if cache[n] != cache1[n] and items + [n] not in result:
                    result.append(items + [n])

        ans = result
    return ans
permutations([1, 2, 2])
> [[1, 2, 2], [2, 1, 2], [2, 2, 1]]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.