Thursday, October 23, 2008

Project Euler Problem 34 Factorions

[root@www ~]# python thirtyfour.py
145
40585
Started at: Thu Oct 23 13:20:38 2008 Ended at: Thu Oct 23 13:21:23 2008
[root@www ~]# cat thirtyfour.py
# -*- coding: utf-8 -*-
"""
<+ MODULE_NAME +>
Project Euler Problem Set
<+ DESCRIPTION +>
Solutions in Python to the problems at http://projecteuler.net

Licensed under the Creative Commons license; see http://creativecommons.org for more details. In short, this means you can freely reuse, modify and distribute this program, also commercially, for as long you provide a proper attribution.

Copyright by Jonathan Mark, jonathanmark.com/aristede.com, jmark@aristede.com

>>> print 881 + 1
882

"""
import time
starttime = time.asctime()

# 145 is a curious number, as 1! + 4! + 5! = 1 + 24 + 120 = 145.

# Find the sum of all numbers which are equal to the sum of the factorial of their digits.

# Note: as 1! = 1 and 2! = 2 are not sums they are not included.

# An 8 digit number cannot be less than 10,000,000

# Nine factorial is 362880

# So the largest sum-of-factorials which an 8 digit number can have

# is 8 * 362880 = 2903040

# Similarly for 9 or more digits.

# Therefore a curious number can have at most seven digits.

# The largest curious number can be at most 7 * 362880 = 2540160


def factorial(n):
"""
Factorial function

>>> factorial(5)
120

>>> factorial(1)
1

>>> factorial(0)
1

"""
if n < 0:
return -999999
elif n < 2:
return 1
else:
return n * factorial(n - 1)

class precalc:
def __init__(self):
"""
Stores precalculated factorials

>>> x = precalc()
>>> x.ten[0]
1

"""
self.ten = [1] + [factorial(n) for n in range(1,10)]

pc = precalc()
fact = pc.ten

def getFact(n):
"""
Reads precalculated single-digit factorials

>>> getFact(5)
120

>>> getFact(4)
24

>>> getFact(0)
1

>>> getFact(8)
40320


"""

return fact[int(n)]


def sumOfFactorialsHelper(n):
"""
Find the sum of the factorials in each digit of n

>>> sumOfFactorialsHelper(145)
[1, 24, 120]

mathworld.wolfram.com says that there are only four
factorions: 1,2, 145 and 40585

>>> sumOfFactorialsHelper(40585)
[24, 1, 120, 40320, 120]



"""
s = str(n)
digits = [s[i] for i in range(len(s))]
factDigits = map(getFact, digits)
return factDigits

for n in range(10, 2540161):
if sum(sumOfFactorialsHelper(n)) == n:
print n



print "Started at: ", starttime, " Ended at: ",time.asctime()

if __name__ == "__main__":
import doctest
doctest.testmod()

Saturday, October 18, 2008

Project Euler Problem 33 Curious Fractions

[root@www ~]# python thirtythree.py
[16, 64]
[19, 95]
[26, 65]
[49, 98]
There were 4 curious fractions.
Started at: Sat Oct 18 21:53:18 2008 Ended at: Sat Oct 18 21:53:18 2008
[root@www ~]# cat thirtythree.py
from __future__ import division
"""
<+ MODULE_NAME +>
Project Euler Problem Set
<+ DESCRIPTION +>
Solutions in Python to the problems at http://projecteuler.net

Licensed under the Creative Commons license; see http://creativecommons.org for more details. In short, this means you can freely reuse, modify and distribute this program, also commercially, for as long you provide a proper attribution.

Copyright by Jonathan Mark, jonathanmark.com/aristede.com, jmark@aristede.com

>>> print 881 + 1
882

"""
import time

starttime = time.asctime()

# The fraction 49/98 is a curious fraction,
# as an inexperienced mathematician in attempting to simplify it
# may incorrectly believe that 49/98 = 4/8,

def shortcut(numerator, denominator, n,m):
"""
Tests for a non-zero digit which is in both the two-digit numerator
and the two-digit denominator

>>> shortcut(49, 98, 1,0)
True

>>> shortcut(48,98, 1,0)
False

>>> shortcut(40,80, 1,1)
False

>>> shortcut(77,77,1,1)
False

>>> shortcut(9,99,0,0)
False

>>> shortcut(9,99,0,1)
False

>>> shortcut(11,111, 1,1)
False

"""
if numerator < 10 or numerator > 99 or denominator < 10 or denominator > 99:
return False
if numerator >= denominator:
return False
if str(numerator)[n] == str(denominator)[m]:
if str(numerator)[n] == '0':
return False
else:
return True
else:
return False

def flip(n):
"""
Turns a zero into a one and a one into a zero

>>> flip(0)
1

>>> flip(1)
0

"""

return (n + 1) % 2

def testShortcut(numerator, denominator,n,m):
"""
Tests to see whether applying a shortcut produces
an incorrect answer.

First make sure that Python's division is working properly
>>> 1/2
0.5

>>> testShortcut(49,98,1,0)
[49, 98]

>>> testShortcut(49,98,0,1)
False

>>> testShortcut(49,88,0,0)
False

"""
if shortcut(numerator, denominator, n,m):
num = int(str(numerator)[flip(n)])
den = int(str(denominator)[flip(m)])
if den == 0:
return False
if numerator/denominator == num/den:
return [numerator,denominator]
return False

def countCurious():
"""
returns how many curious numbers there are with two digit
numerators and denominators

"""

count = 0
for numerator in range(10,100):
for denominator in range(numerator,100):
for n in range(2):
for m in range(2):
result = testShortcut(numerator, denominator,n,m)
if result:
print result
count += 1
return "There were " + str(count) + " curious fractions."

print(countCurious())
print "Started at: ", starttime, " Ended at: ",time.asctime()

if __name__ == "__main__":
import doctest
doctest.testmod()

Tuesday, October 14, 2008

Project Euler Pandigital Numbers Problem 32

[root@www ~]# python thirtytwo.py
45228
Started at: Tue Oct 14 13:38:21 2008 Ended at: Tue Oct 14 13:38:27 2008
[root@www ~]# cat thirtytwo.py
# -*- coding: utf-8 -*-
"""
<+ MODULE_NAME +>
Project Euler Problem Set
<+ DESCRIPTION +>
Solutions in Python to the problems at http://projecteuler.net

Licensed under the Creative Commons license; see http://creativecommons.org for more details. In short, this means you can freely reuse, modify and distribute this program, also commercially, for as long you provide a proper attribution.

Copyright by Jonathan Mark, jonathanmark.com/aristede.com, jmark@aristede.com

>>> print 881 + 1
882

"""
import time
starttime = time.asctime()


def testExactlyOnce(s,n):
"""
Returns true if a digit appears exactly once in a string
and the string contains no zeroes

>>> testExactlyOnce('11234567890',1)
False

>>> testExactlyOnce('123456789',0)
False

>>> testExactlyOnce('123456789',9)
True

>>> testExactlyOnce('123450',6)
False

"""

s = str(s)
if s.count(str(0)) > 0:
return False
if s.count(str(n)) == 1:
return True
else:
return False


def concatenate(n1,n2):
"""
Multiplies n1 * n2 and concatenates result to n1 and n2

>>> concatenate(186,39)
'186397254'

"""

return str(n1)+ str(n2) + str(n1*n2)

def testBothPandigital(n):
"""
tests whether a five digit number, when split into
numbers of lengths 4,1 and 3,2, produces Pandigital
numbers

>>> testBothPandigital(18639)
7254

"""
tot = 0
if testPandigital(concatenate(int(str(n)[:4]),int(str(n)[4]))):
tot = int(str(n)[:4]) * int(str(n)[4])
if testPandigital(concatenate(int(str(n)[:3]),int(str(n)[3:]))):
tot = int(str(n)[:3]) * int(str(n)[3:])
return tot

def testPandigital(s):
"""
tests whether n1, n2 and n1*n2 cof concatenate(int(str(n)[:4]),int(str(n)[4]):
contain each of the digits
0 - 9 exactly once.

>>> testPandigital('186397254')
True

>>> testPandigital('2323')
False

"""

for i in range(1,10):
if testExactlyOnce(s,i) == False:
return False
return True

def unique100000():
"""
return a range consisting of all numbers less than 100000
which do not contain any zeroes and in which no digit
appears more than one time.

>>> len(unique100000())
15120

"""

numbers = []
for n in range(11111,100000):
unique = True
for i in range(len(str(n))):
if not testExactlyOnce(str(n), int(str(n)[i])):
unique = False
if str(n).count('0') > 0:
unique = False
if unique:
numbers.append(n)
return numbers

final ={}

for n in unique100000():
if testBothPandigital(n) > 1111:
final[testBothPandigital(n)] = 0
print sum(final.keys())


print "Started at: ", starttime, " Ended at: ",time.asctime()

if __name__ == "__main__":
import doctest
doctest.testmod()

Sunday, October 12, 2008

Problem 31 Project Euler British currency combinations

[root@www ~]# python thirtyone.py
73682
Started at: Sun Oct 12 18:26:02 2008 Ended at: Sun Oct 12 18:26:02 2008
[root@www ~]# cat thirtyone.py
# -*- coding: utf-8 -*-
"""
<+ MODULE_NAME +>
Project Euler Problem Set
<+ DESCRIPTION +>
Solutions in Python to the problems at http://projecteuler.net

Licensed under the Creative Commons license; see http://creativecommons.org for more details. In short, this means you can freely reuse, modify and distribute this program, also commercially, for as long you provide a proper attribution.

Copyright by Jonathan Mark, jonathanmark.com/aristede.com, jmark@aristede.com

>>> print 881 + 1
882

"""
import time
starttime = time.asctime()
count = 0
# 2p, 5p, 10p, 20p, 50p, £1 (100p) and £2 (200p).
for p5 in range(41):
for p10 in range (21):
for p20 in range(11):
for p50 in range(5):
for p100 in range(3):
for p200 in range(2):
sum = p5*5 + p10*10 + p20*20 + p50*50 + p100*100 + p200*200
if (sum <= 200):
count += (200 -sum)//2 + 1

print count


print "Started at: ", starttime, " Ended at: ",time.asctime()

if __name__ == "__main__":
import doctest
doctest.testmod()

Saturday, October 11, 2008

Project Euler Sum Of Powers Problem 30

[root@www ~]# python thirty.py
4150
4151
54748
92727
93084
194979
The total is 443839
Started at: Sat Oct 11 10:53:50 2008 Ended at: Sat Oct 11 10:54:01 2008
[root@www ~]# cat thirty.py
# -*- coding: utf-8 -*-
"""
<+ MODULE_NAME +>
Project Euler Problem Set
<+ DESCRIPTION +>
Solutions in Python to the problems at http://projecteuler.net

Licensed under the Creative Commons license; see http://creativecommons.org for more details. In short, this means you can freely reuse, modify and distribute this program, also commercially, for as long you provide a proper attribution.

Copyright by Jonathan Mark, jonathanmark.com/aristede.com, jmark@aristede.com

>>> print 881 + 1
882

"""
import time
starttime = time.asctime()

# A 7 digit number must equal at least 1,000,000.
# The sum of the fifth powers of a 7-digit number cannot be
# greater than 7*9**5 equals about 420,000.
# Using similar reasoning n > 7, no number which equals the sum
# of the fifth powers of its digits can have more than six digits.

def sumOfPowers(p,n):
"""takes each digit of a number, raises it to the pth power,
and sums it.

>>> sumOfPowers(5,123)
276

"""

s = str(n)
tot = 0
for i in range(len(s)):
tot += int(s[i])**p
return tot

sum = 0
for n in range(2, 1000000):
if n == sumOfPowers(5,n):
print n
sum += n

print "The total is", sum






print "Started at: ", starttime, " Ended at: ",time.asctime()

if __name__ == "__main__":
import doctest
doctest.testmod()

Friday, October 10, 2008

Project Euler 29 Unique Exponentiation

[root@www ~]# python twentynine.py
9183
Started at: Fri Oct 10 20:34:29 2008 Ended at: Fri Oct 10 20:34:29 2008
[root@www ~]# cat twentynine.py
# -*- coding: utf-8 -*-
"""
<+ MODULE_NAME +>
Project Euler Problem Set
<+ DESCRIPTION +>
Solutions in Python to the problems at http://projecteuler.net

Licensed under the Creative Commons license; see http://creativecommons.org for more details. In short, this means you can freely reuse, modify and distribute this program, also commercially, for as long you provide a proper attribution.

Copyright by Jonathan Mark, jonathanmark.com/aristede.com, jmark@aristede.com

>>> print 881 + 1
882

"""
import time
starttime = time.asctime()

results = {}

for a in range(2,101):
for b in range(2,101):
results[a**b] = 0

print len(results)





print "Started at: ", starttime, " Ended at: ",time.asctime()

if __name__ == "__main__":
import doctest
doctest.testmod()

Wednesday, October 8, 2008

Project Euler Problem 28 diagonals

root@www ~]# python twentyeight.py
669171001
Started at: Wed Oct 8 22:40:25 2008 Ended at: Wed Oct 8 22:40:25 2008
[root@www ~]# cat twentyeight.py
# -*- coding: utf-8 -*-
"""
<+ MODULE_NAME +>
Project Euler Problem Set
<+ DESCRIPTION +>
Solutions in Python to the problems at http://projecteuler.net

Licensed under the Creative Commons license; see http://creativecommons.org for more details. In short, this means you can freely reuse, modify and distribute this program, also commercially, for as long you provide a proper attribution.

Copyright by Jonathan Mark, jonathanmark.com/aristede.com, jmark@aristede.com

>>> print 881 + 1
882

"""
import time
starttime = time.asctime()


def listOddSquare(N):
"""
Returns list of odd squares for the first N odd numbers starting
at 3

>>> sum(listOddSquare(2))
34

>>> sum(listOddSquare(1))
9

"""

x = range(1,(N +1) * 2)
oddSquare = map(lambda x: x * x, x)
oddSquare = filter(lambda x: x % 2 == 1, oddSquare)
oddSquare = oddSquare[1:]
return oddSquare

def listEvenSquarePlusOne(N):
"""
Returns list of square-plus-one for the first N even numbers starting
at 2.

>>> sum(listEvenSquarePlusOne(2))
22

>>> sum(listEvenSquarePlusOne(1))
5

"""
evenSquarePlusOne = filter(lambda x: x % 2 == 0, range(1,(N + 1) * 2 ))
evenSquarePlusOne = map(lambda x: x*x + 1, evenSquarePlusOne)
return evenSquarePlusOne

def listUpperLeft(N):
"""
for returning average of listOddSquare and listEvenSquarePlusOne

>>> upperLeft(2)
28

>>> upperLeft(1)
7

"""


return listOddSquare(N) + listEvenSquarePlusOne(N)

def upperLeft(N):
return sum(listUpperLeft(N))/2

def listLowerRight(N):
"""Returns n-th element of listEvenSquarePlusOne minus n

>>> sum(listLowerRight(2))
16

>>> sum(listLowerRight(1))
3

"""
return [listEvenSquarePlusOne(N)[i] - (2*(i + 1) ) for i in range(N)]

def total(N):
"""Return sum of diagonals except that center is only counted once

>>> total(2)
101


"""

return sum(listEvenSquarePlusOne(N) + listOddSquare(N) + listLowerRight(N)) + upperLeft(N) + 1

print total(500)

print "Started at: ", starttime, " Ended at: ",time.asctime()

if __name__ == "__main__":
import doctest
doctest.testmod()
[root@www ~]#