Moved 1 to 5 to Python and learned a ton.
parent
414cf4b074
commit
b246d56acd
|
@ -1,6 +1,6 @@
|
|||
todo.txt
|
||||
euler.sublime-workspace
|
||||
euler.sublime-project
|
||||
euler-python.sublime-project
|
||||
euler-python.sublime-workspace
|
||||
*.swp
|
||||
__pycache__
|
||||
.ipynb_checkpoints
|
||||
|
|
|
@ -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()))
|
|
@ -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())
|
|
@ -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()))
|
|
@ -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
|
|
@ -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()))
|
|
@ -0,0 +1,5 @@
|
|||
def euler_006():
|
||||
return 0
|
||||
|
||||
assert(euler_006() == 233168)
|
||||
print("e006.py: {}".format(euler_006()))
|
|
@ -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
|
|
@ -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()
|
|
@ -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)
|
|
@ -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()
|
|
@ -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))
|
|
@ -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()
|
Loading…
Reference in New Issue