Это комбинация (а) поиска списков [k_1, ..., k_n]
, так что каждый k_i
равен либо k_(i-1)
или k_(i-1)+1
, и (б) нахождения уникальных перестановок этих списков.
Первое можно сделать с помощью рекурсивной функции:
def combinations(n, k=0):
if n > 1:
yield from ([k] + res for i in (0, 1)
for res in combinations(n-1, k+i))
else:
yield [k]
Для списков с n
элементами будет 2^(n-1)
таких комбинаций:
>>> list(combinations(2))
[[0, 0], [0, 1]]
>>> list(combinations(3))
[[0, 0, 0], [0, 0, 1], [0, 1, 1], [0, 1, 2]]
>>> list(combinations(4))
[[0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 1], [0, 0, 1, 2], [0, 1, 1, 1], [0, 1, 1, 2], [0, 1, 2, 2], [0, 1, 2, 3]]
Объедините это с itertools.permutations
и отфильтруйте дубликаты, чтобы получить окончательный результат:
import itertools
def all_combinations(n):
return (x for combs in combinations(n)
for x in set(itertools.permutations(combs)))
Пример:
>>> list(all_combinations(3))
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (1, 0, 0), (0, 1, 1), (1, 0, 1), (1, 1, 0), (0, 1, 2), (0, 2, 1), (1, 0, 2), (1, 2, 0), (2, 0, 1), (2, 1, 0)]
>>> sum(1 for _ in all_combinations(4))
75
>>> sum(1 for _ in all_combinations(5))
541
Примечание: Генерация всех n!
перестановок, а затем фильтрация дубликатовможет быть очень расточительным даже для немного больших значений n
.Существуют более разумные способы создания только уникальных перестановок, которые можно использовать вместо itertools.permutations
, см., Например, здесь или здесь .