Sunday, December 5, 2010

Puzzle 4

What's the largest palindrome number that is the product of two three digit numbers.

This time I have one of the better solutions:


def nextpal(low,high,reversed=False):
assert low < high

if reversed:
candidate = high
final = low
increment = -1
else:
candidate = low
final = high
increment = 1
while candidate != final:
if str(candidate) == str(candidate)[-1::-1]:
yield candidate
candidate += increment

def getfactor(low,high,target):
for test in range(low,high):
if not target % test:
residual = target/test
if residual in range(low,high):
return test, residual
return None

if __name__ == "__main__":
from time import time
start = time()
pal = nextpal(10000,1000000, reversed=True)
while True:
target = pal.next()
result = getfactor(100,1000,target)
if result:
print target
print result
break
end = time()
print end - start


Most started from the factors to see if they built palindromes. Much better to go the other way; far fewer tests (the 94th palindrome succeeded, so less than 9400 calculations. The cast to string for the palindrome test is easy, but is it efficient?

The most interesting items on the discussion were the Pytho one-liner:

max(map(lambda s: bool(s) and max(s) or 0, [(filter(lambda n: n == int(str(n)[::-1]), map(lambda n: i*n, range(999, 99, -1)))) for i in range(999, 99, -1)]))

and the pen-and-paper solution

You can also do this with pen and paper. You have a number:

(100a + 10b + c)(100d + 10e + f)

Which is a palindrone. This factors out to:

100cd + 10ce + cf +
1000bd + 100be + 10bf +
10000ad + 1000ae + 100af

Assuming the first digit is 9, then cf must be equal to nine.
Also, both a and d must then be equal to nine. The only ways
to make the last digit of the product of two integers 9 would
be if those integers were either of:

1 and 9
3 and 3
7 and 7

So, both numbers must start with 9, end with either 1, 3, 7,
or 9, and one of them must be divisible by 11. The only
numbers divisible by 11 from 900 - 1000 are:

902
913
924
935
946
957
968
979
990

You can discard all of those that do not end in either 1, 3,
7, or 9, and you are left with:

913
957
979

So now the presumed answer is either:

(900 + 10 + 3)(900 + 10x + 3)
(900 + 50 + 7)(900 + 10x + 7)
(900 + 70 + 9)(900 + 10x + 1)

Factoring all those out, you get:

810000 + 9000x + 2700 + 9000 + 100x + 30 + 2700 + 30x + 9
824439 + 9130x

Now, for the first digit 824439 + 9130x to be 9, x must be 9
(if x were 8, then 824439 + 9130x = 897479, and the first
digit is 8). And so you have 913 * 993, which is the answer.
You can factor the others out to see if they produce a bigger
answer, which they don't.

Saturday, December 4, 2010

Puzzle 3 without cheating

I am about 2800 times slower than the cheat I downloaded. But I get the right answer, and in a tolerable time (30 seconds). Pure brute forcing this seems like it would take much longer.


from sys import argv
from math import sqrt
from time import time

# PRIME GENERATOR

def nextprime():
""" generate next prime """

myprimes = [2]
candidate = 3
yield 2
while True:
factors = factorize(candidate,myprimes)
if len(factors.keys()) == 1:
myprimes.append(candidate)
yield candidate
candidate += 2

def primesupto(upto):
""" collect primes from the generator"""

result = []
primes = nextprime()
p = None
while not p or p < upto:
if p:
result.append(p)
p = primes.next()
return result

def factorize(target,allprimes=None,verbose=False):
""" get factors of an integer

this works but is very slow if the primes aren't cached """

factors = {}
upto = int(sqrt(target))
residual = target
prime = nextprime()

if allprimes:
prime = allprimes.__iter__()

while True: # get factors and multiplicities up to sqrt(N)
try:
factor = prime.next()
except StopIteration:
break
if factor > upto:
break
while not residual % factor:
residual /= factor
factors[factor] = factors.get(factor,0) + 1

if residual > 1: # if anything is left it is the sole prime factor > sqrt(N)
factors[residual] = 1

return factors

if __name__ == "__main__":
target = int(argv[1]) # get target from command line
upto = sqrt(target)
starttime = time()
allprimes = primesupto(upto)
print max(factorize(int(argv[1]),allprimes).keys())
endtime = time()
print endtime - starttime


Update:

Best answer, wow!


from time import time
from sys import argv

n = int(argv[1])
d = 3

starttime = time()
while (d * d < n):
if n % d == 0: n /= d
else: d += 2
endtime = time()
print n
print endtime - startime


Runs in 0.7 msec. I feel like a complete idiot now. Oh well, it was interesting anyway.

Cheating, sorta

What is the largest prime factor of the number 600851475143 ?

from os import system
from os.path import isfile
from sys import argv

try:
import numbthy
except:
if not isfile("numbthy.py"): # don't mess with it if it's already there and broken
system("wget http://userpages.umbc.edu/~rcampbel/Computers/Python/lib/numb
thy.py")
import numbthy

f = numbthy.factors(int(argv[1]))
if f: print f[-1]

Level 2

I'm mostly at level 2 in this chart, except for IDEs. I don't really use them. I like aquamacs for an editor but even there I'm not good at it. I'm also pretty lame at version control, never having had the opportunity to work closely with others; hence never having run into a merge problem in real life.

I read some of the sorts of books he calls level 3.

Friday, December 3, 2010

Number Two

Python shines on this one. Find the sum of all the even-valued terms in the Fibonacci sequence which do not exceed four million.


from itertools import ifilterfalse

def fib(n1=1,n2=1,fmax=4000000):
"terminating fibonacci sequence"

assert 0 < n1 <= n2 < fmax
l = [n2,n1]
while l:
if l[0] < fmax/2:
l.append(sum(l))
yield l.pop(0)

if __name__ == "__main__":
print sum(ifilterfalse(lambda x: x % 2,fib()))

Euler Project

prob 1

A one-liner.


>>> sum([i for i in range(10) if not (i%3 and i%5)])
23
>>> sum([i for i in range(1000) if not (i%3 and i%5)])
233168


So it's surprisingly interesting:


>>> for n in range(1,9):
... print sum([i for i in range(10**n) if not (i%3 and i%5)])
...
23
2318
233168
23331668
2333316668
233333166668
23333331666668
2333333316666668


Can't even come up with a succinct notation for the theorem, never mind any idea how to prove it.

Tuesday, November 30, 2010

Moving notes to self

Notes to self or those interested in my daily pain will be moved to http://aardvarknoplay.blogspot.com/ . Old notes being moved.

This blog will actually have content that others may find interesting.