Вот пример решения в Scala, которое я подробно объясню:
/**
example: index:=15, list:=(1, 2, 3, 4)
*/
def permutationIndex (index: Int, list: List [Int]) : List [Int] =
if (list.isEmpty) list else {
val len = list.size // len = 4
val max = fac (len) // max = 24
val divisor = max / len // divisor = 6
val i = index / divisor // i = 2
val el = list (i)
el :: permutationIndex (index - divisor * i, list.filter (_ != el)) }
Поскольку Scala не так хорошо известна, я думаю, что мне нужно объяснить последнюю строку алгоритма, котораякроме того, довольно самоочевиден.
el :: elist
создает новый список из элемента el и списка elist.Элист это рекурсивный вызов.
list.filter (_ != el)
- это просто список без элемента el.
Проверьте это исчерпывающе с небольшим списком:
(0 to fac (4) - 1).map (permutationIndex (_, List (1, 2, 3, 4))).mkString ("\n")
Проверьте скорость большего списка с 2 примерами:
scala> permutationIndex (123456789, (1 to 12).toList)
res45: List[Int] = List(4, 2, 1, 5, 12, 7, 10, 8, 11, 6, 9, 3)
scala> permutationIndex (123456790, (1 to 12).toList)
res46: List[Int] = List(4, 2, 1, 5, 12, 7, 10, 8, 11, 9, 3, 6)
Результат появляется сразу на 5лет ноутбукСуществует 479 001 600 перестановок для Списка из 12 элементов, но с 100 или 1000 элементами это решение все равно должно работать быстро - вам просто нужно будет использовать BigInt в качестве индекса.
Как это работает?Я сделал графическое изображение, для визуализации примера, список (1, 2, 3, 4) и индекс 15:
![enter image description here](https://i.stack.imgur.com/n6NoU.png)
Список из 4 элементов производит 4!перестановки (= 24).Мы выбираем произвольный индекс от 0 до 4! -1, скажем, 15.
Мы можем визуализировать все перестановки в дереве с первым узлом из 1..4.Мы делим 4!на 4 и видим, что каждый первый узел ведет к 6 поддеревьям.Если мы разделим наш индекс 15 на 6, результат будет 2, а значение в нашем нулевом списке с индексом 2 равно 3. Итак, первый узел - 3, а остальная часть нашего списка - (1, 2, 4),Вот таблица, показывающая, как 15 приводит к элементу с индексом 2 в массиве / списке / что угодно:
0 1 2 3 4 5 | 6 ... 11 | 12 13 14 15 16 17 | 18 ... 23
0 | 1 | 2 | 3
| | 0 1 2 3 4 5 |
Теперь мы вычтем 12, первый элемент ячейки (12 ... 17)для последних 3 элементов, которые имеют 6 возможных перестановок, и посмотрите, как 15 отображается на 3. Число 3 теперь ведет к индексу массива 1, который был элементом 2, поэтому результат пока равен List (3, 2, ...).
| 0 1 | 2 3 | 4 5 |
| 0 | 1 | 3 |
| 0 1 |
Опять же, мы вычитаем 2 и заканчиваем двумя оставшимися элементами с 2 перестановками и индексом (0, 3), сопоставляя значения (1, 4).Мы видим, что второй элемент, принадлежащий 15 сверху, соответствует значению 3, а оставшийся элемент для последнего шага - другой:
| 0 | 1 |
| 0 | 3 |
| 3 | 0 |
Наш результат - List (3, 2, 4, 1) или индексы (2, 1, 3, 0).Проверка всех индексов по порядку показывает, что они дают все перестановки по порядку.