Moved 1 to 5 to Python and learned a ton.
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,6 +1,6 @@
|
|||||||
todo.txt
|
todo.txt
|
||||||
euler.sublime-workspace
|
euler-python.sublime-project
|
||||||
euler.sublime-project
|
euler-python.sublime-workspace
|
||||||
*.swp
|
*.swp
|
||||||
__pycache__
|
__pycache__
|
||||||
.ipynb_checkpoints
|
.ipynb_checkpoints
|
||||||
|
|||||||
11
python/e001.py
Normal file
11
python/e001.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
def get_sum_of_natural_dividable_by_3_and_5_below(m):
|
||||||
|
return sum([x for x in range(m) if x % 3 == 0 or x % 5 == 0])
|
||||||
|
|
||||||
|
|
||||||
|
def euler_001():
|
||||||
|
return get_sum_of_natural_dividable_by_3_and_5_below(1000)
|
||||||
|
|
||||||
|
|
||||||
|
assert(get_sum_of_natural_dividable_by_3_and_5_below(10) == 23)
|
||||||
|
assert(euler_001() == 233168)
|
||||||
|
print("e001.py: {}".format(euler_001()))
|
||||||
24
python/e002.py
Normal file
24
python/e002.py
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
from lib_fibonacci import fibonacci_generator_smaller
|
||||||
|
|
||||||
|
|
||||||
|
def euler_002():
|
||||||
|
fs = [f for f in fibonacci_generator_smaller(4000000) if f % 2 == 0]
|
||||||
|
return sum(fs)
|
||||||
|
|
||||||
|
|
||||||
|
assert(euler_002() == 4613732)
|
||||||
|
print("e002.py: {}".format(euler_002()))
|
||||||
|
|
||||||
|
|
||||||
|
def euler_002_simple():
|
||||||
|
""" Sometimes it is nice to keep it simple. Instead of using three
|
||||||
|
library functions just implement one straightforward function. """
|
||||||
|
r, a, b = 0, 0, 1
|
||||||
|
while b < 4000000:
|
||||||
|
if b % 2 == 0:
|
||||||
|
r += b
|
||||||
|
a, b = b, a + b
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
assert(euler_002() == euler_002_simple())
|
||||||
9
python/e003.py
Normal file
9
python/e003.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from lib_prime import prime_factors
|
||||||
|
|
||||||
|
|
||||||
|
def euler_003():
|
||||||
|
return prime_factors(600851475143)[-1]
|
||||||
|
|
||||||
|
|
||||||
|
assert(euler_003() == 6857)
|
||||||
|
print("e003.py: {}".format(euler_003()))
|
||||||
66
python/e004.py
Normal file
66
python/e004.py
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
from lib_misc import is_palindrome
|
||||||
|
|
||||||
|
|
||||||
|
def euler_004():
|
||||||
|
r = 0
|
||||||
|
for a in range(999, 99, -1):
|
||||||
|
for b in range(a, r // a, -1):
|
||||||
|
if is_palindrome(a * b) and a * b > r:
|
||||||
|
r = a * b
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def euler_004_original():
|
||||||
|
""" The solution that I came up with originally. """
|
||||||
|
r = 0
|
||||||
|
for a in range(999, 99, -1):
|
||||||
|
if a * a < r:
|
||||||
|
break
|
||||||
|
for b in range(a, 99, -1):
|
||||||
|
c = a * b
|
||||||
|
if c > r and is_palindrome(c):
|
||||||
|
r = c
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def euler_004_forum():
|
||||||
|
"""
|
||||||
|
A solution from etatsui in the project Euler forum.
|
||||||
|
It is impressive to see how much fast it is relying on
|
||||||
|
mathematical tricks:
|
||||||
|
11(9091a + 910b + 100c) = mn;
|
||||||
|
Let:
|
||||||
|
11 * 10 < m < 11 * 90
|
||||||
|
"""
|
||||||
|
for a in range(9, 0, -1):
|
||||||
|
for b in range(9, -1, -1):
|
||||||
|
for c in range(9, -1, -1):
|
||||||
|
num = 9091 * a + 910 * b + 100 * c
|
||||||
|
for m in range(90, 9, -1):
|
||||||
|
if num % m == 0:
|
||||||
|
if num / m > 999:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
result = num * 11
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
assert(euler_004() == 906609)
|
||||||
|
print("e004.py: {}".format(euler_004()))
|
||||||
|
|
||||||
|
|
||||||
|
def time_tests():
|
||||||
|
from timeit import timeit
|
||||||
|
assert(euler_004() == 906609)
|
||||||
|
assert(euler_004_original() == 906609)
|
||||||
|
assert(euler_004_forum() == 906609)
|
||||||
|
|
||||||
|
print(timeit(lambda: euler_004(), number=100))
|
||||||
|
print(timeit(lambda: euler_004_original(), number=100))
|
||||||
|
print(timeit(lambda: euler_004_forum(), number=100))
|
||||||
|
|
||||||
|
|
||||||
|
# time_tests()
|
||||||
|
# 0.5044660240000667
|
||||||
|
# 0.7896412069985672
|
||||||
|
# 0.04794573199978913
|
||||||
29
python/e005.py
Normal file
29
python/e005.py
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
from lib_prime import prime_factors_count
|
||||||
|
from lib_misc import product
|
||||||
|
|
||||||
|
|
||||||
|
def get_number_divisible(n):
|
||||||
|
""" Returns the lowest number that is divisible
|
||||||
|
by all numbers from 1 to n. We calculate the factors
|
||||||
|
for all numbers and make sure that the minimum number
|
||||||
|
for each factor is included in the solution. """
|
||||||
|
f = {}
|
||||||
|
for i in range(2, n + 1):
|
||||||
|
for prime, count in prime_factors_count(i).items():
|
||||||
|
try:
|
||||||
|
f[prime] = max(f[prime], count)
|
||||||
|
except KeyError:
|
||||||
|
f[prime] = count
|
||||||
|
n = product([prime**count for prime, count in f.items()])
|
||||||
|
return n
|
||||||
|
|
||||||
|
|
||||||
|
assert(get_number_divisible(10) == 2520)
|
||||||
|
|
||||||
|
|
||||||
|
def euler_005():
|
||||||
|
return get_number_divisible(20)
|
||||||
|
|
||||||
|
|
||||||
|
assert(euler_005() == 232792560)
|
||||||
|
print("e005.py: {}".format(euler_005()))
|
||||||
5
python/e006.py
Normal file
5
python/e006.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
def euler_006():
|
||||||
|
return 0
|
||||||
|
|
||||||
|
assert(euler_006() == 233168)
|
||||||
|
print("e006.py: {}".format(euler_006()))
|
||||||
44
python/lib_fibonacci.py
Normal file
44
python/lib_fibonacci.py
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
def fibonacci_generator():
|
||||||
|
"""
|
||||||
|
Fibonacci generator function that starts with 1, 1, 2, 3, ...
|
||||||
|
|
||||||
|
:returns: generator that yields fibonacci numbers
|
||||||
|
"""
|
||||||
|
a = 0
|
||||||
|
b = 1
|
||||||
|
yield b
|
||||||
|
while True:
|
||||||
|
a, b = b, (a + b)
|
||||||
|
yield b
|
||||||
|
|
||||||
|
|
||||||
|
def fibonacci_generator_smaller(n):
|
||||||
|
"""
|
||||||
|
|
||||||
|
:param n: generator yields all fibonacci numbers smaller n
|
||||||
|
:returns: generator that yields fibonacci numbers
|
||||||
|
|
||||||
|
"""
|
||||||
|
g = fibonacci_generator()
|
||||||
|
x = next(g)
|
||||||
|
while x < n:
|
||||||
|
yield x
|
||||||
|
x = next(g)
|
||||||
|
|
||||||
|
|
||||||
|
def fibonacci_nth(n):
|
||||||
|
"""
|
||||||
|
|
||||||
|
:param n: index of fibonacci that should be returned
|
||||||
|
:returns: nth fibonacci number
|
||||||
|
|
||||||
|
"""
|
||||||
|
if n < 1:
|
||||||
|
return 0
|
||||||
|
g = fibonacci_generator()
|
||||||
|
i = 1
|
||||||
|
x = next(g)
|
||||||
|
while i < n:
|
||||||
|
i += 1
|
||||||
|
x = next(g)
|
||||||
|
return x
|
||||||
35
python/lib_fibonacci_tests.py
Normal file
35
python/lib_fibonacci_tests.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
import unittest
|
||||||
|
try:
|
||||||
|
from .lib_fibonacci import fibonacci_generator
|
||||||
|
from .lib_fibonacci import fibonacci_generator_smaller
|
||||||
|
from .lib_fibonacci import fibonacci_nth
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
from lib_fibonacci import fibonacci_generator
|
||||||
|
from lib_fibonacci import fibonacci_generator_smaller
|
||||||
|
from lib_fibonacci import fibonacci_nth
|
||||||
|
|
||||||
|
|
||||||
|
class TestFibonacciMethods(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_fibonacci_generator(self):
|
||||||
|
g = fibonacci_generator()
|
||||||
|
fs = [next(g) for _ in range(10)]
|
||||||
|
self.assertEqual(fs, [1, 1, 2, 3, 5, 8, 13, 21, 34, 55])
|
||||||
|
self.assertNotEqual(fs, [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55])
|
||||||
|
|
||||||
|
def test_fibonacci_generator_smaller(self):
|
||||||
|
g = fibonacci_generator_smaller(20)
|
||||||
|
self.assertEqual(list(g), [1, 1, 2, 3, 5, 8, 13])
|
||||||
|
|
||||||
|
def test_fibonacci_nth(self):
|
||||||
|
self.assertEqual(fibonacci_nth(0), 0)
|
||||||
|
self.assertEqual(fibonacci_nth(1), 1)
|
||||||
|
self.assertEqual(fibonacci_nth(2), 1)
|
||||||
|
self.assertEqual(fibonacci_nth(3), 2)
|
||||||
|
self.assertEqual(fibonacci_nth(4), 3)
|
||||||
|
self.assertEqual(fibonacci_nth(5), 5)
|
||||||
|
self.assertEqual(fibonacci_nth(6), 8)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
78
python/lib_misc.py
Normal file
78
python/lib_misc.py
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
def get_digits_reversed(n):
|
||||||
|
"""
|
||||||
|
Returns a list of digits for n.
|
||||||
|
"""
|
||||||
|
digits, rest = [], n
|
||||||
|
while rest != 0:
|
||||||
|
digits.append(rest % 10)
|
||||||
|
rest //= 10
|
||||||
|
return digits
|
||||||
|
|
||||||
|
|
||||||
|
def is_palindrome_string(n):
|
||||||
|
"""
|
||||||
|
Checks whether n is a palindrome number
|
||||||
|
with a string based algorithm.
|
||||||
|
|
||||||
|
:param n: number to check
|
||||||
|
:returns: boolean
|
||||||
|
|
||||||
|
"""
|
||||||
|
s = str(n)
|
||||||
|
return s == s[::-1]
|
||||||
|
|
||||||
|
|
||||||
|
def is_palindrome_integer(n):
|
||||||
|
"""
|
||||||
|
Checks whether n is a palindrome number
|
||||||
|
with an integer based algorithm.
|
||||||
|
|
||||||
|
:param n: number to check
|
||||||
|
:returns: boolean
|
||||||
|
"""
|
||||||
|
digits = get_digits_reversed(n)
|
||||||
|
digits_count = len(digits)
|
||||||
|
for i in range(digits_count // 2):
|
||||||
|
if digits[i] != digits[digits_count - i - 1]:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def time_is_palindrom():
|
||||||
|
""" I just want to check which option is faster. """
|
||||||
|
from timeit import timeit
|
||||||
|
print(timeit(lambda: is_palindrome_integer(82445254428), number=100000))
|
||||||
|
print(timeit(lambda: is_palindrome_string(82445254428), number=100000))
|
||||||
|
# > 0.42330633100027626
|
||||||
|
# > 0.07605635199979588
|
||||||
|
|
||||||
|
|
||||||
|
is_palindrome = is_palindrome_string
|
||||||
|
|
||||||
|
|
||||||
|
def get_item_counts(l):
|
||||||
|
"""
|
||||||
|
Counts how often each element is part of the list.
|
||||||
|
|
||||||
|
:param l: a list
|
||||||
|
:returns: a dictionary
|
||||||
|
"""
|
||||||
|
d = {}
|
||||||
|
for e in l:
|
||||||
|
try:
|
||||||
|
d[e] += 1
|
||||||
|
except KeyError:
|
||||||
|
d[e] = 1
|
||||||
|
return d
|
||||||
|
|
||||||
|
|
||||||
|
def product(l):
|
||||||
|
"""
|
||||||
|
Calculates the product of all items in the list.
|
||||||
|
|
||||||
|
:param l: a list
|
||||||
|
:returns: a number that is the product of all elements in the list
|
||||||
|
"""
|
||||||
|
from functools import reduce
|
||||||
|
import operator
|
||||||
|
return reduce(operator.mul, l, 1)
|
||||||
47
python/lib_misc_tests.py
Normal file
47
python/lib_misc_tests.py
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import unittest
|
||||||
|
try:
|
||||||
|
from .lib_misc import is_palindrome_integer
|
||||||
|
from .lib_misc import is_palindrome_string
|
||||||
|
from .lib_misc import get_digits_reversed
|
||||||
|
from .lib_misc import get_item_counts
|
||||||
|
from .lib_misc import product
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
from lib_misc import is_palindrome_integer
|
||||||
|
from lib_misc import is_palindrome_string
|
||||||
|
from lib_misc import get_digits_reversed
|
||||||
|
from lib_misc import get_item_counts
|
||||||
|
from lib_misc import product
|
||||||
|
|
||||||
|
|
||||||
|
class TestPrimeMethods(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_is_palindrome_integer(self):
|
||||||
|
self.assertEqual(is_palindrome_integer(2), True)
|
||||||
|
self.assertEqual(is_palindrome_integer(888), True)
|
||||||
|
self.assertEqual(is_palindrome_integer(9009), True)
|
||||||
|
self.assertEqual(is_palindrome_integer(23), False)
|
||||||
|
self.assertEqual(is_palindrome_integer(9008), False)
|
||||||
|
|
||||||
|
def test_is_palindrome_string(self):
|
||||||
|
self.assertEqual(is_palindrome_string(2), True)
|
||||||
|
self.assertEqual(is_palindrome_string(888), True)
|
||||||
|
self.assertEqual(is_palindrome_string(9009), True)
|
||||||
|
self.assertEqual(is_palindrome_string(23), False)
|
||||||
|
self.assertEqual(is_palindrome_string(9008), False)
|
||||||
|
|
||||||
|
def test_get_digits_reversed(self):
|
||||||
|
self.assertEqual(get_digits_reversed(3), [3])
|
||||||
|
self.assertEqual(get_digits_reversed(1234), [4, 3, 2, 1])
|
||||||
|
self.assertEqual(get_digits_reversed(1000), [0, 0, 0, 1])
|
||||||
|
|
||||||
|
def test_get_item_counts(self):
|
||||||
|
self.assertEqual(get_item_counts([]), {})
|
||||||
|
self.assertEqual(get_item_counts([1, 1, 3]), {1: 2, 3: 1})
|
||||||
|
|
||||||
|
def test_product(self):
|
||||||
|
self.assertEqual(product([2, 4, 8]), 64)
|
||||||
|
self.assertEqual(product([]), 1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
27
python/lib_prime.py
Normal file
27
python/lib_prime.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
try:
|
||||||
|
from lib_misc import get_item_counts
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
from .lib_misc import get_item_counts
|
||||||
|
|
||||||
|
|
||||||
|
def prime_factors(n):
|
||||||
|
# TODO: Look into using a prime wheel instead.
|
||||||
|
factors = []
|
||||||
|
rest = n
|
||||||
|
divisor = 2
|
||||||
|
while rest % divisor == 0:
|
||||||
|
factors.append(divisor)
|
||||||
|
rest //= divisor
|
||||||
|
divisor = 3
|
||||||
|
while divisor * divisor <= rest:
|
||||||
|
while rest % divisor == 0:
|
||||||
|
factors.append(divisor)
|
||||||
|
rest //= divisor
|
||||||
|
divisor += 2
|
||||||
|
if rest != 1:
|
||||||
|
factors.append(rest)
|
||||||
|
return factors
|
||||||
|
|
||||||
|
|
||||||
|
def prime_factors_count(n):
|
||||||
|
return get_item_counts(prime_factors(n))
|
||||||
25
python/lib_prime_tests.py
Normal file
25
python/lib_prime_tests.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import unittest
|
||||||
|
try:
|
||||||
|
from .lib_prime import prime_factors
|
||||||
|
from .lib_prime import prime_factors_count
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
from lib_prime import prime_factors
|
||||||
|
from lib_prime import prime_factors_count
|
||||||
|
|
||||||
|
|
||||||
|
class TestPrimeMethods(unittest.TestCase):
|
||||||
|
|
||||||
|
def test_prime_factors(self):
|
||||||
|
self.assertEqual(prime_factors(2), [2])
|
||||||
|
self.assertEqual(prime_factors(5), [5])
|
||||||
|
self.assertEqual(prime_factors(10), [2, 5])
|
||||||
|
self.assertEqual(prime_factors(13), [13])
|
||||||
|
self.assertEqual(prime_factors(147), [3, 7, 7])
|
||||||
|
|
||||||
|
def test_prime_factors_count(self):
|
||||||
|
self.assertEqual(prime_factors_count(2), {2: 1})
|
||||||
|
self.assertEqual(prime_factors_count(147), {3: 1, 7: 2})
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
Reference in New Issue
Block a user