Sunday, July 12th, 2009...15:55
Project Euler Problem #4
As I work through these projecteuler problems, it’s become apparent that my brain tends towards a particular style of solution. When I know one way to solve a problem, I tend to just implement it, as I want to get to the next one. In the future, I’m going to start trying to find multiple solutions right off the bat, before I check to see if I’ve answered the problem correctly. Here’s an example; problem 4 requested the largest number that is a product of two 3 digit numbers as well as being a palindrome.
It’s obvious the answer will be <= 999 x 999 and >= 100 x 100. I came up with this solution relatively quickly:
def findLargestPalindrome():
factorA = 999
factorB = factorA
maxToCheck = 100
maxPalindrome = 0
while factorA > maxToCheck:
factorB = factorA
while factorB > maxToCheck:
temp = factorA * factorB
if temp < maxPalindrome:
maxToCheck = factorB
break
else:
tempStr = str(temp)
if tempStr == tempStr[::-1]:
maxToCheck = factorB
maxPalindrome = temp
break
factorB -= 1
factorA -= 1
return maxPalindrome
Answer: 906609. 100 iterations took 2.677 seconds
I want to call out that the syntax for reversing a string, string[::-1] is pretty odd looking. It asks for the representation of the string from the beginning to the end in -1 steps/strides. So position -1 from the start is the end, and then position -1 from the end is the second to last character, etc.
When I was playing with Erlang, one of the fundamental aspects of the language is the notion of single assignment i.e. a variable can only be assigned to once, and then never changes. Obviously the code above reassigns numerous variables over and over again during execution. As an exercise I decided to re-write the answer recursively and pretend I was constrained by the single assignment rule.
def findLargestPalindrome2(factorA, factorB, maxToCheck, maxPalindrome):
if factorA < maxToCheck:
return maxPalindrome
elif factorB < maxToCheck:
newFactor = factorA - 1
return findLargestPalindrome2(newFactor, newFactor, maxToCheck, maxPalindrome)
else:
candidate = factorA * factorB
if candidate < maxPalindrome:
newFactor = factorA - 1
return findLargestPalindrome2(newFactor, newFactor, factorB, maxPalindrome)
else:
tempStr = str(candidate)
if tempStr == tempStr[::-1]:
newFactor = factorA - 1
return findLargestPalindrome2(newFactor, newFactor, factorB, candidate)
else:
return findLargestPalindrome2(factorA, factorB - 1, maxToCheck, maxPalindrome)
This function has a very different look to it as state must be passed to each recursive call. I also apparently exceeded the default recursion limit and had to: sys.setrecursionlimit(7000). The recursive solution is also almost twice as slow.
Answer: 906609. 100 iterations took 4.350 seconds
This is also another example of a problem that can be optimized further, and even solved with pen and paper...
Comments are closed.