Вот быстрый алгоритм, который создает короткую строку, содержащую все перестановки. Я уверен, что он дает самый короткий ответ, но у меня нет полного доказательства в руке.
Объяснение. Ниже представлено дерево всех перестановок. Изображение неполное; представьте, что дерево продолжается вечно направо.
1 --+-- 12 --+-- 123 ...
| |
| +-- 231 ...
| |
| +-- 312 ...
|
+-- 21 --+-- 213 ...
|
+-- 132 ...
|
+-- 321 ...
Узлы на уровне к этого дерева являются все перестановки длины к. Кроме того, перестановки находятся в определенном порядке с множеством перекрытия между каждой перестановкой и ее соседями сверху и снизу.
Чтобы быть точным, первый ребенок каждого узла находится путем простого добавления следующего символа в конец. Например, первый ребенок из 213 будет равен 2134. Остальные детей находятся путем поворота к первому ребенку на один символ в времени. Вращающийся 2134 будет производить 1342, 3421, 4213.
Принимая все узлы на заданном уровне и нанизывая их вместе, перекрывая как можно больше, производит строки 1, 121, 123121321 и т.д.
В длина n-я строка в этой последовательности - the sum for x=1 to n of x!. (Вы можете это доказать, наблюдая, сколько не перекрывается между соседними перестановками. Братья и сестры перекрываются во всех, кроме одного символа, первые кузены перекрываются во всех, кроме двух символов, и т. Д.)
Эскиз доказательства. Я не полностью доказал, что это лучшее решение, но вот пример того, как будет продолжаться доказательство. Во-первых, показывают, что любая строка, содержащая п различных перестановок имеет длину н - 1. Тогда показывают, что при добавлении любой строки, содержащей п +1 различных перестановок имеет длину 2 п + 1. То есть, добавив еще один перестановка будет стоить вам двух цифр. Продолжить путем вычисления минимальной длины строк, содержащих п P г и п Р г + 1 различных перестановок, до п!. Короче говоря, эта последовательность оптимальна, потому что вы не можете сделать ее хуже где-нибудь в надежде сделать ее лучше где-нибудь еще. Это уже локально оптимально во всем мире. Все движения вынуждены.
Алгоритм. Учитывая весь этот фон, алгоритм очень прост. Пройдите это дерево до нужной глубины и соедините все узлы на этой глубине.
К счастью, нам фактически не нужно строить дерево в памяти.
def build(node, s):
"""String together all descendants of the given node at the target depth."""
d = len(node) # depth of this node. depth of "213" is 3.
n = len(s) # target depth
if d == n - 1:
return node + s[n - 1] + node # children of 213 join to make "2134213"
else:
c0 = node + s[d] # first child node
children = [c0[i:] + c0[:i] for i in range(d + 1)] # all child nodes
strings = [build(c, s) for c in children] # recurse to the desired depth
for j in range(1, d + 1):
strings[j] = strings[j][d:] # cut off overlap with previous sibling
return ''.join(strings) # join what's left
def stringContainingAllPermutationsOf(s):
return build(s[:1], s)
Производительность. Вышеупомянутый код уже намного быстрее моего другого решения, и он много режет и вставляет большие строки, которые вы можете оптимизировать. Алгоритм может быть выполнен для выполнения во времени и в памяти, пропорциональных размеру выхода.
Интересная проблема. Я даже не знаю длины самой короткой такой последовательности. Нижняя граница равна n! + n - 1, так как существует n! различные перестановки и каждая из них должна иметь отличную начальную точку в последовательности. Верхняя оценка - это (n-1)! (2n-1), которую вы можете добиться путем произвольного выбора элемента, а затем навязывания «полного цикла» каждой перестановки, заканчивающейся этим элементом, т. Е. Почти двух копий перестановки, как в 234512345. Есть (n-1)! такие перестановки, и каждый цикл имеет длину (2n-1). –
Ответ, который вы выбрали, является правильным (и оптимальным) ответом. – Xolve