diff --git a/python/e020.py b/python/e020.py index fd30246..a9e8c67 100644 --- a/python/e020.py +++ b/python/e020.py @@ -1,7 +1,11 @@ +from lib_misc import factorial + + def euler_020(): - return 0 + f_100 = factorial(100) + return sum(map(int, str(f_100))) if __name__ == "__main__": - assert(euler_020() == 1074) + assert(euler_020() == 648) print("e020.py: {}".format(euler_020())) diff --git a/python/e021.py b/python/e021.py new file mode 100644 index 0000000..fdbf656 --- /dev/null +++ b/python/e021.py @@ -0,0 +1,15 @@ +from lib_misc import sum_proper_divisors + + +def euler_021(): + t = 0 + for n in range(1, 10000): + s = sum_proper_divisors(n) + if n != s and n == sum_proper_divisors(s): + t += n + return t + + +if __name__ == "__main__": + assert(euler_021() == 31626) + print("e021.py: {}".format(euler_021())) diff --git a/python/e022.py b/python/e022.py new file mode 100644 index 0000000..601ff17 --- /dev/null +++ b/python/e022.py @@ -0,0 +1,17 @@ +def get_score_for_name(name): + return sum([ord(c) - ord('A') + 1 for c in name if not c == '"']) + + +def euler_022(): + with open('../txt/EulerProblem022.txt', 'r') as f: + names = f.read().split(',') + names.sort() + s = sum([(i + 1) * get_score_for_name(name) + for i, name in enumerate(names)]) + return s + + +if __name__ == "__main__": + assert(get_score_for_name('COLIN') == 53) + assert(euler_022() == 871198282) + print("e022.py: {}".format(euler_022())) diff --git a/python/e023.py b/python/e023.py index 97c262b..afc82d1 100644 --- a/python/e023.py +++ b/python/e023.py @@ -1,40 +1,28 @@ -import math - - -def get_proper_divisors(n): - proper_divisors = set([1]) - for i in range(2, int(math.sqrt(n)) + 1): - if n % i == 0: - proper_divisors.add(i) - proper_divisors.add(n / i) - return proper_divisors +from lib_misc import sum_proper_divisors def is_abundant(n): - return sum(get_proper_divisors(n)) > n + return sum_proper_divisors(n) > n -def get_abundant_numbers_smaller(n): - ret = [] - for i in range(1, n): - if is_abundant(i): - ret.append(i) - return ret - - -def is_sum_of_two_abundant(n, abundant_numbers): - abundant_numbers_set = set(abundant_numbers) - for a1 in abundant_numbers: - if a1 > n: +def is_sum_of_two_abundant(n, abundant_numbers, abundant_numbers_set): + for a in abundant_numbers: + if a > n: return False - elif (n - a1) in abundant_numbers_set: + d = n - a + if d in abundant_numbers_set: return True - - + return False + + +def euler_023(): + abundant_numbers = [n for n in range(1, 28123 + 1) if is_abundant(n)] + abundant_numbers_set = set(abundant_numbers) + return sum([n for n in range(1, 28123 + 1) + if not is_sum_of_two_abundant(n, abundant_numbers, + abundant_numbers_set)]) + + if __name__ == "__main__": - abundant_numbers = get_abundant_numbers_smaller(30000) - cannot_be_written_as_sum_of_abundant = [] - for i in range(28129): - if not is_sum_of_two_abundant(i, abundant_numbers): - cannot_be_written_as_sum_of_abundant.append(i) - print(sum(cannot_be_written_as_sum_of_abundant)) + print("e023.py: {}".format(euler_023())) + assert(euler_023() == 4179871) diff --git a/python/e024.py b/python/e024.py index 85587c1..5b5ceee 100644 --- a/python/e024.py +++ b/python/e024.py @@ -1,2 +1,31 @@ from itertools import permutations -print("".join(list(permutations("0123456789"))[1000000-1])) + + +def euler_024_library(): + return int("".join(list(permutations("0123456789"))[1000000 - 1])) + + +def permutations_(iterable): + if not iterable: + yield iterable + for i in range(len(iterable)): + elem = iterable[i:i + 1] + rest = iterable[:i] + iterable[i + 1:] + for ps in permutations_(rest): + yield elem + ps + + +def n_th(generator, n): + for i in range(n): + next(generator) + return next(generator) + + +def euler_024(): + g = permutations_("0123456789") + return int(n_th(g, 1000000 - 1)) + + +if __name__ == "__main__": + print("e024.py: {}".format(euler_024())) + assert(euler_024() == 2783915460) diff --git a/python/e025.py b/python/e025.py index 4768c88..f2690fb 100644 --- a/python/e025.py +++ b/python/e025.py @@ -1,109 +1,12 @@ -from copy import deepcopy -from itertools import islice +from lib_fibonacci import fibonacci_generator -def primes(n): - """ Nice way to calculate primes. Should be fast. """ - l = range(2, n + 1) - _l = [] - while True: - p = l[0] - if p * p > n: - return _l + l - l = [i for i in l if i % p != 0] - _l.append(p) - - -def calculate_decimal_places(numerator, denominator): - numerator = (numerator - (numerator / denominator) * denominator) * 10 - digits = [] - while True: - digit = numerator / denominator - numerator = (numerator - digit * denominator) * 10 - digits.append(digit) - if digits[-3:] == [0, 0, 0]: - raise StopIteration - yield digit - - -def has_cycle(decimal_places, n): - d = decimal_places - return list(islice(d, 0, n)) == list(islice(d, 0, n)) and \ - list(islice(d, 0, n)) == list(islice(d, 0, n)) - - -def f_025_1(): - """ Second try. I realized that only primes must be - checked. Therefore, my brute force approach worked. """ - l = [] - for d in primes(1000): - for i in range(5, 10000): - decimal_places = calculate_decimal_places(1, d) - if has_cycle(decimal_places, i): - l.append((i, d)) - break - print(max(l)) - - -def calculate_cycle(numerator, denominator): - numerator = (numerator - (numerator / denominator) * denominator) * 10 - remainders = set([]) - while True: - digit = numerator / denominator - remainder = (numerator - digit * denominator) - if remainder in remainders: - raise StopIteration - remainders.add(remainder) - numerator = remainder * 10 - yield digit - - -def f_025_2(): - """ Understood trick with remembering remainder... """ - s = [(len(list(calculate_cycle(1, d))), d) - for d in range(1, 1001)] - print(max(s)) - - -def f_025_3(): - """ Only testing primes... """ - s = [(len(list(calculate_cycle(1, d))), d) - for d in primes(10000)] - print(max(s)) - - -f_025_3() - - -#print([(find_cycle_count(calculate_decimal_places(1, d)), d) -# for d in range(1, 100)]) - -#print(find_cycle_count(calculate_decimal_places(22, 7))) - -#l = [] -#for d in range(1, 1000): -# for i in range(5, 1000): -# decimal_places = calculate_decimal_places(1, d) -# if has_cycle_one_off(decimal_places, i): -# l.append((i, d)) -# break -# decimal_places = calculate_decimal_places(1, d) -# if has_cycle(decimal_places, i): -# l.append((i, d)) -# break - -#def find_cycle_count(decimal_places): -# cycles = [] -# for digit in decimal_places: -# new_cycles = [] -# for cycle in cycles: -# digits, length = cycle -# if digits[0] == digit: -# if len(digits[1:]) == 0: -# return length -# new_cycles.append((digits[1:], length)) -# new_cycles.append((digits + [digit], length + 1)) -# new_cycles.append(([digit], 1)) -# cycles = new_cycles +def euler_025(): + for i, f in enumerate(fibonacci_generator()): + if len(str(f)) >= 1000: + return i + 1 +if __name__ == "__main__": + print("e025.py: {}".format(euler_025())) + assert(euler_025() == 4782) diff --git a/python/e026.py b/python/e026.py index a514a0b..8488278 100644 --- a/python/e026.py +++ b/python/e026.py @@ -1,38 +1,31 @@ -def primes(n): - """ Nice way to calculate primes. Should be fast. """ - l = range(2, n + 1) - _l = [] - while True: - p = l[0] - if p * p > n: - return _l + l - l = [i for i in l if i % p != 0] - _l.append(p) +from itertools import count -def produce_prime(a, b, n, primes): - x = n*n + a*n + b - return x in primes - +def get_cycle_count(nominator, denominator): + assert(nominator == 1) + remainders = {} + remainder = nominator + results = [] + for i in count(): + result = remainder // denominator + remainder = remainder % denominator + results.append(result) + if remainder in remainders: + return i - remainders[remainder] + else: + remainders[remainder] = i + if remainder == 0: + return 0 + remainder *= 10 -def f_027(): - """ n^2 + a*n + b - 1) b must be prime - """ - p6 = set(primes(1000000)) - p3 = primes(1000) - options = [(a, b) - for a in range(1, 1000, 2) - for b in p3] - - print(len(options)) - for n in range(100): - options = [(a, b) - for a, b in options - if produce_prime(a, b, n, p6)] - print(options) - print(len(options)) +def euler_026(): + return max([(get_cycle_count(1, i), i) for i in range(1, 1000)])[1] -f_027() +if __name__ == "__main__": + assert(get_cycle_count(1, 7) == 6) + assert(get_cycle_count(1, 10) == 0) + assert(get_cycle_count(1, 6) == 1) + print("e026.py: {}".format(euler_026())) + assert(euler_026() == 983) diff --git a/python/lib_misc.py b/python/lib_misc.py index 876b2ab..d232d79 100644 --- a/python/lib_misc.py +++ b/python/lib_misc.py @@ -134,4 +134,46 @@ def collatz_sequence_length(n): return length + collatz_sequence_length(n // 2) +@lru_cache(maxsize=10000) +def factorial(n): + if n == 1: + return 1 + return n * factorial(n - 1) + +def proper_divisors(n): + """ + Returns the list of divisors for n excluding n. + """ + if n < 2: + return [] + divisors = [1, ] + d = 2 + while d * d <= n: + if n % d == 0: + divisors.append(d) + d += 1 + # Ignore first element and iterate list backwards. + for d in divisors[1:][::-1]: + q = n // d + if q != d: + divisors.append(q) + return divisors + + +def sum_proper_divisors(n): + """ + Returns the sum of proper divisors of a number. + """ + if n < 2: + return 0 + s = 1 + d = 2 + while d * d <= n: + if n % d == 0: + s += d + q = n // d + if q != d: + s += q + d += 1 + return s diff --git a/python/lib_misc_tests.py b/python/lib_misc_tests.py index 423448e..03d02b2 100644 --- a/python/lib_misc_tests.py +++ b/python/lib_misc_tests.py @@ -9,6 +9,8 @@ try: from .lib_misc import even, odd from .lib_misc import collatz_sequence from .lib_misc import collatz_sequence_length + from .lib_misc import factorial + from .lib_misc import proper_divisors, sum_proper_divisors except ModuleNotFoundError: from lib_misc import is_palindrome_integer from lib_misc import is_palindrome_string @@ -19,6 +21,8 @@ except ModuleNotFoundError: from lib_misc import even, odd from lib_misc import collatz_sequence from lib_misc import collatz_sequence_length + from lib_misc import factorial + from lib_misc import proper_divisors, sum_proper_divisors class TestPrimeMethods(unittest.TestCase): @@ -70,6 +74,27 @@ class TestPrimeMethods(unittest.TestCase): [13, 40, 20, 10, 5, 16, 8, 4, 2, 1]) self.assertEqual(collatz_sequence_length(13), 10) + def test_factorial(self): + self.assertEqual(factorial(1), 1) + self.assertEqual(factorial(3), 6) + self.assertEqual(factorial(10), 3628800) + + def test_proper_divisors(self): + self.assertEqual(proper_divisors(0), []) + self.assertEqual(proper_divisors(1), []) + self.assertEqual(proper_divisors(2), [1]) + self.assertEqual(proper_divisors(4), [1, 2]) + self.assertEqual(proper_divisors(220), [ + 1, 2, 4, 5, 10, 11, 20, 22, 44, 55, 110]) + + def test_sum_proper_divisors(self): + self.assertEqual(sum_proper_divisors(0), 0) + self.assertEqual(sum_proper_divisors(1), 0) + self.assertEqual(sum_proper_divisors(2), 1) + self.assertEqual(sum_proper_divisors(3), 1) + self.assertEqual(sum_proper_divisors(220), 284) + self.assertEqual(sum_proper_divisors(284), 220) + if __name__ == '__main__': unittest.main() diff --git a/python/lib_prime.py b/python/lib_prime.py index 0e029dd..fa901d6 100644 --- a/python/lib_prime.py +++ b/python/lib_prime.py @@ -8,6 +8,8 @@ except ModuleNotFoundError: def prime_factors(n): """ + Returns a list of prime factors for n. + :param n: number for which prime factors should be returned """ # TODO: Look into using a prime wheel instead. @@ -30,10 +32,12 @@ def prime_factors(n): def prime_factors_count(n): """ + Returns a dictionay of primes where each key is a prime + and the value how many times that prime is part of the factor of n. :param n: numober for which prime factor counts are returned - :returns: a dict where they key is a prime vactor and the value - the count of how of that value occurs + :returns: a dict where they key is a prime and the value + the count of how often that value occurs """ return get_item_counts(prime_factors(n))