From
Project Euler:
A permutation is an ordered arrangement of objects. For example, 3124 is one possible permutation of the digits 1, 2, 3 and 4. If all of the permutations are listed numerically or alphabetically, we call it lexicographic order. The lexicographic permutations of 0, 1 and 2 are:
012 021 102 120 201 210
What is the millionth lexicographic permutation of the digits 0, 1, 2, 3, 4, 5, 6, 7, 8 and 9?
This one can be done by brute force on a modern computer, but that would be way too slow. We can use a little deduction here to reduce the amount of computation we need. We know that there are 10! possible permutations of the digits 0 through 9, or 3 628 800 values. If we fix the first digit, we know that there are 9! or 362 880 numbers starting with that digit. Since the numbers are in numerical order, we konw that the first 362 880 start with 0, the next 362 880 start with 1, etc. Therefore the first permutation that starts with 1 is the 362 881st number, the first that starts with 2 is the 725 761st number (2 times 362 880, plus one), and the first that starts with 3 is the 1 008 641st number. Since this is greater than a million, we know that the first digit must be 2.
Once we've found the first digit, we know that all the digits starting with 2 begin at position 725 761. If we subtract that from a million we get 274 239, which is the number of positions from the current one we want to get to. Here we can repeat the same logic as before: there are 8! (or 40 320) possible permutations starting with 20, and another 8! starting with 21, etc. Dividing 8! into 274 239 we get 6 plus some change. This does not mean that 6 is the next digit, but rather the 6th element of our remaining available digits is the next one. Since we've removed 2, the 6th element is 7. So we have 27 as the first two digits of the millionth permutation.
We can now repeat the logic again: We subtract 6 times 8! from 274 239 to get 32 319. Fixing the first digit we have 7! (or 5040) remaining possible numbers, we do the quotient and get the index, and loop through.
To write this out:
# use zero-based indexing:
999 999 = 2 * 9! + 274 239
# Available digits are (0 1 2 3 4 5 6 7 8 9), index 2 is 2
274 239 = 6 * 8! + 32 319
# Available digits are (0 1 3 4 5 6 7 8 9), index 6 is 7
32 319 = 6 * 7! + 2079
# Available digits are (0 1 3 4 5 6 8 9), index 6 is 8
2079 = 2 * 6! + 639
# Available digits are (0 1 3 4 5 6 9), index 2 is 3
...
Here's the code to do this:
(defn nth-lex-permutation
"Gets the nth permutation from the set of digits up to max."
[n max]
(loop [available-numbers (range max)
; Keep track of the digits we've used so far as a number.
digits-so-far 0
; Keep track of where we are within the current range of
; permutations.
index-from-offset (- n 1)
; Track how many permutations there are when we fix one digit.
num-permutations (factorial (- max 1))
; Track the factorial we're multiplying by.
current-f (- max 1)]
(if
(empty? available-numbers) digits-so-far
; index-from-offset = idx * num-permutations + next-offset
; idx is the index of the next digit within available-numbers.
(let [idx (quot index-from-offset num-permutations)
value (nth available-numbers idx)
remaining-numbers (remove #(= % value) available-numbers)
next-digits (+ (* 10 digits-so-far) value)
next-offset (rem index-from-offset num-permutations)
next-num-permutations
(if (zero? current-f)
0
(/ num-permutations current-f))]
(recur remaining-numbers
next-digits
next-offset
next-num-permutations
(- current-f 1))))))
This runs very fast:
$ lein run
Processing...
Value is: 2783915460
"Elapsed time: 2.049982 msecs"