Project Euler Problem #24:

Problem #24 is similar to Problem #15 in that they both commonly appear on introductory math competitions such as the AMC 10/12 and Mathcounts. However, unlike Problem #15, this question is pretty annoying. The question reads:

Project Euler Problem 24: Lexicographic permutations
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?

I don’t know why, but I’ve always found this problem to be incredibly annoying as you are very susceptible to “off by one” errors while solving it. Here’s my solution:

Solution #1: Brute Force Approach

The key is to notice that there are precisely 9! (9 factorial) permutations that begin with 0, 9! that begin with 1, and so on, with each starting digit getting exactly 9! permutations. Once a starting digit is chosen, the problem reverts to a version with 1 less potential digit (but the index of the permutation decreases based on the starting digit).

A starting digit of 0 covers permutations 1 – 9!, a starting digit of 1 covers permutations 9!+1 – 2*9!, and so on. I found this pretty annoying, so I shifted my solution (and the problem) to a 0-based index where by decreasing the index (1,000,000) by 1, I could instead say that 0 covers permutations 0 – (9!-1), 1 covers permutations 9! – (2*9!-1), and so on. After making this change, I just repeatedly used the first observation to find each digit moving from left to right. Here is an implementation of this method in Python 2.7:

 '''
 Author: Walker Kroubalkian
 Brute Force Approach to Project Euler Problem #24
 '''

 import time

 def factorial(n):
     total = 1
     for c in range(2,n+1):
         total*=c
     return total

 def projectEulerProblemTwentyFour(n, x):
     myFactorials = []
     for i in range(x):
         myFactorials.append(factorial(x-1-i))

     myString = ""
     n-=1
     counter = 0

     possibleDigits = []
     for i in range(x):
         possibleDigits.append(str(i))

     while(counter<x and len(possibleDigits)>1):
         total = 0
         thisDigit = -1
         while(total<=n):
             total+=myFactorials[counter]
             thisDigit+=1
         myString += possibleDigits[thisDigit]
         n-=(total-myFactorials[counter])
         possibleDigits.pop(thisDigit)
         counter+=1

     myString+=possibleDigits[0]

     return myString

 start = time.time()
 print projectEulerProblemTwentyFour(1000000, 10)
 print ("--- %s seconds ---" % (time.time()-start))

 '''
 Prints

 2783915460
 --- 2.90870666504e-05 seconds ---

 for input of n = 1000000, x = 10
 '''

And with that, we’re done with this very annoying problem. It always takes me a bit of troubleshooting to solve this problem, so I’m glad I got it done.

Thanks for reading!

Published by Walker Kroubalkian

My name is Walker Kroubalkian. I really enjoy math, computer science, and hiking.

Leave a comment

Design a site like this with WordPress.com
Get started