diff --git a/DIRECTORY.md b/DIRECTORY.md index 6a3d31709ed6..1dd1289ab36c 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -552,8 +552,6 @@ * Problem 12 * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_12/sol1.py) * [Sol2](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_12/sol2.py) - * Problem 120 - * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_120/sol1.py) * Problem 13 * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_13/sol1.py) * Problem 14 @@ -599,7 +597,7 @@ * Problem 29 * [Solution](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_29/solution.py) * Problem 30 - * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_30/sol1.py) + * [Soln](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_30/soln.py) * Problem 31 * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_31/sol1.py) * [Sol2](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_31/sol2.py) @@ -635,8 +633,6 @@ * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_47/sol1.py) * Problem 48 * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_48/sol1.py) - * Problem 49 - * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_49/sol1.py) * Problem 52 * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_52/sol1.py) * Problem 53 diff --git a/data_structures/linked_list/print_reverse.py b/data_structures/linked_list/print_reverse.py index c46f228e7260..c3a72b6b7a23 100644 --- a/data_structures/linked_list/print_reverse.py +++ b/data_structures/linked_list/print_reverse.py @@ -1,4 +1,4 @@ -from typing import List +# Program to print the elements of a linked list in reverse class Node: @@ -8,63 +8,48 @@ def __init__(self, data=None): def __repr__(self): """Returns a visual representation of the node and all its following nodes.""" - string_rep = [] + string_rep = "" temp = self while temp: - string_rep.append(f"{temp.data}") + string_rep += f"<{temp.data}> ---> " temp = temp.next - return "->".join(string_rep) + string_rep += "" + return string_rep -def make_linked_list(elements_list: List): +def make_linked_list(elements_list): """Creates a Linked List from the elements of the given sequence - (list/tuple) and returns the head of the Linked List. - >>> make_linked_list([]) - Traceback (most recent call last): - ... - Exception: The Elements List is empty - >>> make_linked_list([7]) - 7 - >>> make_linked_list(['abc']) - abc - >>> make_linked_list([7, 25]) - 7->25 - """ + (list/tuple) and returns the head of the Linked List.""" + + # if elements_list is empty if not elements_list: raise Exception("The Elements List is empty") - current = head = Node(elements_list[0]) - for i in range(1, len(elements_list)): - current.next = Node(elements_list[i]) + # Set first element as Head + head = Node(elements_list[0]) + current = head + # Loop through elements from position 1 + for data in elements_list[1:]: + current.next = Node(data) current = current.next return head -def print_reverse(head_node: Node) -> None: - """Prints the elements of the given Linked List in reverse order - >>> print_reverse([]) - >>> linked_list = make_linked_list([69, 88, 73]) - >>> print_reverse(linked_list) - 73 - 88 - 69 - """ - if head_node is not None and isinstance(head_node, Node): +def print_reverse(head_node): + """Prints the elements of the given Linked List in reverse order""" + + # If reached end of the List + if head_node is None: + return None + else: + # Recurse print_reverse(head_node.next) print(head_node.data) -def main(): - from doctest import testmod - - testmod() - - linked_list = make_linked_list([14, 52, 14, 12, 43]) - print("Linked List:") - print(linked_list) - print("Elements in Reverse:") - print_reverse(linked_list) - - -if __name__ == "__main__": - main() +list_data = [14, 52, 14, 12, 43] +linked_list = make_linked_list(list_data) +print("Linked List:") +print(linked_list) +print("Elements in Reverse:") +print_reverse(linked_list) diff --git a/maths/allocation_number.py b/maths/allocation_number.py index d419e74d01ff..4e74bb2e6950 100644 --- a/maths/allocation_number.py +++ b/maths/allocation_number.py @@ -1,28 +1,37 @@ -""" -In a multi-threaded download, this algorithm could be used to provide -each worker thread with a block of non-overlapping bytes to download. -For example: - for i in allocation_list: - requests.get(url,headers={'Range':f'bytes={i}'}) -""" from __future__ import annotations def allocation_num(number_of_bytes: int, partitions: int) -> list[str]: """ Divide a number of bytes into x partitions. - :param number_of_bytes: the total of bytes. - :param partitions: the number of partition need to be allocated. - :return: list of bytes to be assigned to each worker thread + In a multi-threaded download, this algorithm could be used to provide + each worker thread with a block of non-overlapping bytes to download. + For example: + for i in allocation_list: + requests.get(url,headers={'Range':f'bytes={i}'}) + + parameter + ------------ + : param number_of_bytes + : param partitions + + return + ------------ + : return: list of bytes to be assigned to each worker thread + + Examples: + ------------ >>> allocation_num(16647, 4) - ['1-4161', '4162-8322', '8323-12483', '12484-16647'] - >>> allocation_num(50000, 5) - ['1-10000', '10001-20000', '20001-30000', '30001-40000', '40001-50000'] + ['0-4161', '4162-8322', '8323-12483', '12484-16647'] + >>> allocation_num(888, 888) + Traceback (most recent call last): + ... + ValueError: partitions can not >= number_of_bytes! >>> allocation_num(888, 999) Traceback (most recent call last): ... - ValueError: partitions can not > number_of_bytes! + ValueError: partitions can not >= number_of_bytes! >>> allocation_num(888, -4) Traceback (most recent call last): ... @@ -30,16 +39,16 @@ def allocation_num(number_of_bytes: int, partitions: int) -> list[str]: """ if partitions <= 0: raise ValueError("partitions must be a positive number!") - if partitions > number_of_bytes: - raise ValueError("partitions can not > number_of_bytes!") + if partitions >= number_of_bytes: + raise ValueError("partitions can not >= number_of_bytes!") bytes_per_partition = number_of_bytes // partitions - allocation_list = [] - for i in range(partitions): - start_bytes = i * bytes_per_partition + 1 - end_bytes = ( - number_of_bytes if i == partitions - 1 else (i + 1) * bytes_per_partition - ) - allocation_list.append(f"{start_bytes}-{end_bytes}") + allocation_list = [f"0-{bytes_per_partition}"] + for i in range(1, partitions - 1): + length = f"{bytes_per_partition * i + 1}-{bytes_per_partition * (i + 1)}" + allocation_list.append(length) + allocation_list.append( + f"{(bytes_per_partition * (partitions - 1)) + 1}-" f"{number_of_bytes}" + ) return allocation_list diff --git a/maths/extended_euclidean_algorithm.py b/maths/extended_euclidean_algorithm.py index e7087636ce09..fe81bcfaf71d 100644 --- a/maths/extended_euclidean_algorithm.py +++ b/maths/extended_euclidean_algorithm.py @@ -3,72 +3,59 @@ Finds 2 numbers a and b such that it satisfies the equation am + bn = gcd(m, n) (a.k.a Bezout's Identity) - -https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm """ # @Author: S. Sharma # @Date: 2019-02-25T12:08:53-06:00 # @Email: silentcat@protonmail.com -# @Last modified by: pikulet -# @Last modified time: 2020-10-02 +# @Last modified by: PatOnTheBack +# @Last modified time: 2019-07-05 import sys -from typing import Tuple -def extended_euclidean_algorithm(a: int, b: int) -> Tuple[int, int]: +def extended_euclidean_algorithm(m, n): """ Extended Euclidean Algorithm. Finds 2 numbers a and b such that it satisfies the equation am + bn = gcd(m, n) (a.k.a Bezout's Identity) - - >>> extended_euclidean_algorithm(1, 24) - (1, 0) - - >>> extended_euclidean_algorithm(8, 14) - (2, -1) - - >>> extended_euclidean_algorithm(240, 46) - (-9, 47) - - >>> extended_euclidean_algorithm(1, -4) - (1, 0) - - >>> extended_euclidean_algorithm(-2, -4) - (-1, 0) - - >>> extended_euclidean_algorithm(0, -4) - (0, -1) - - >>> extended_euclidean_algorithm(2, 0) - (1, 0) - """ - # base cases - if abs(a) == 1: - return a, 0 - elif abs(b) == 1: - return 0, b - - old_remainder, remainder = a, b - old_coeff_a, coeff_a = 1, 0 - old_coeff_b, coeff_b = 0, 1 - - while remainder != 0: - quotient = old_remainder // remainder - old_remainder, remainder = remainder, old_remainder - quotient * remainder - old_coeff_a, coeff_a = coeff_a, old_coeff_a - quotient * coeff_a - old_coeff_b, coeff_b = coeff_b, old_coeff_b - quotient * coeff_b - - # sign correction for negative numbers - if a < 0: - old_coeff_a = -old_coeff_a - if b < 0: - old_coeff_b = -old_coeff_b - - return old_coeff_a, old_coeff_b + a = 0 + a_prime = 1 + b = 1 + b_prime = 0 + q = 0 + r = 0 + if m > n: + c = m + d = n + else: + c = n + d = m + + while True: + q = int(c / d) + r = c % d + if r == 0: + break + c = d + d = r + + t = a_prime + a_prime = a + a = t - q * a + + t = b_prime + b_prime = b + b = t - q * b + + pair = None + if m > n: + pair = (a, b) + else: + pair = (b, a) + return pair def main(): @@ -76,9 +63,9 @@ def main(): if len(sys.argv) < 3: print("2 integer arguments required") exit(1) - a = int(sys.argv[1]) - b = int(sys.argv[2]) - print(extended_euclidean_algorithm(a, b)) + m = int(sys.argv[1]) + n = int(sys.argv[2]) + print(extended_euclidean_algorithm(m, n)) if __name__ == "__main__": diff --git a/other/doomsday.py b/other/doomsday.py deleted file mode 100644 index d8fe261156a1..000000000000 --- a/other/doomsday.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/bin/python3 -# Doomsday algorithm info: https://en.wikipedia.org/wiki/Doomsday_rule - -DOOMSDAY_LEAP = [4, 1, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5] -DOOMSDAY_NOT_LEAP = [3, 7, 7, 4, 2, 6, 4, 1, 5, 3, 7, 5] -WEEK_DAY_NAMES = { - 0: "Sunday", - 1: "Monday", - 2: "Tuesday", - 3: "Wednesday", - 4: "Thursday", - 5: "Friday", - 6: "Saturday", -} - - -def get_week_day(year: int, month: int, day: int) -> str: - """Returns the week-day name out of a given date. - - >>> get_week_day(2020, 10, 24) - 'Saturday' - >>> get_week_day(2017, 10, 24) - 'Tuesday' - >>> get_week_day(2019, 5, 3) - 'Friday' - >>> get_week_day(1970, 9, 16) - 'Wednesday' - >>> get_week_day(1870, 8, 13) - 'Saturday' - >>> get_week_day(2040, 3, 14) - 'Wednesday' - - """ - # minimal input check: - assert len(str(year)) > 2, "year should be in YYYY format" - assert 1 <= month <= 12, "month should be between 1 to 12" - assert 1 <= day <= 31, "day should be between 1 to 31" - - # Doomsday algorithm: - century = year // 100 - century_anchor = (5 * (century % 4) + 2) % 7 - centurian = year % 100 - centurian_m = centurian % 12 - dooms_day = ( - (centurian // 12) + centurian_m + (centurian_m // 4) + century_anchor - ) % 7 - day_anchor = ( - DOOMSDAY_NOT_LEAP[month - 1] - if (year % 4 != 0) or (centurian == 0 and (year % 400) == 0) - else DOOMSDAY_LEAP[month - 1] - ) - week_day = (dooms_day + day - day_anchor) % 7 - return WEEK_DAY_NAMES[week_day] - - -if __name__ == "__main__": - import doctest - - doctest.testmod() diff --git a/project_euler/problem_01/sol1.py b/project_euler/problem_01/sol1.py index 2dbb60cdb16f..e81156edaee4 100644 --- a/project_euler/problem_01/sol1.py +++ b/project_euler/problem_01/sol1.py @@ -6,7 +6,7 @@ """ -def solution(n: int = 1000) -> int: +def solution(n): """Returns the sum of all the multiples of 3 or 5 below n. >>> solution(3) diff --git a/project_euler/problem_01/sol2.py b/project_euler/problem_01/sol2.py index 212fd40562d1..8041c7ffa589 100644 --- a/project_euler/problem_01/sol2.py +++ b/project_euler/problem_01/sol2.py @@ -6,7 +6,7 @@ """ -def solution(n: int = 1000) -> int: +def solution(n): """Returns the sum of all the multiples of 3 or 5 below n. >>> solution(3) diff --git a/project_euler/problem_01/sol3.py b/project_euler/problem_01/sol3.py index faa505615924..c0bcbc06ec83 100644 --- a/project_euler/problem_01/sol3.py +++ b/project_euler/problem_01/sol3.py @@ -6,7 +6,7 @@ """ -def solution(n: int = 1000) -> int: +def solution(n): """ This solution is based on the pattern that the successive numbers in the series follow: 0+3,+2,+1,+3,+1,+2,+3. diff --git a/project_euler/problem_01/sol4.py b/project_euler/problem_01/sol4.py index d5e86320da5e..e01dc977d8cf 100644 --- a/project_euler/problem_01/sol4.py +++ b/project_euler/problem_01/sol4.py @@ -6,7 +6,7 @@ """ -def solution(n: int = 1000) -> int: +def solution(n): """Returns the sum of all the multiples of 3 or 5 below n. >>> solution(3) diff --git a/project_euler/problem_01/sol5.py b/project_euler/problem_01/sol5.py index eae62ef5c75c..bd96d965f92d 100644 --- a/project_euler/problem_01/sol5.py +++ b/project_euler/problem_01/sol5.py @@ -8,7 +8,7 @@ """A straightforward pythonic solution using list comprehension""" -def solution(n: int = 1000) -> int: +def solution(n): """Returns the sum of all the multiples of 3 or 5 below n. >>> solution(3) diff --git a/project_euler/problem_01/sol6.py b/project_euler/problem_01/sol6.py index ca08a4a639ab..c9f94b9f77c8 100644 --- a/project_euler/problem_01/sol6.py +++ b/project_euler/problem_01/sol6.py @@ -6,7 +6,7 @@ """ -def solution(n: int = 1000) -> int: +def solution(n): """Returns the sum of all the multiples of 3 or 5 below n. >>> solution(3) diff --git a/project_euler/problem_01/sol7.py b/project_euler/problem_01/sol7.py index 8e53d2a81fb9..a0510b54c409 100644 --- a/project_euler/problem_01/sol7.py +++ b/project_euler/problem_01/sol7.py @@ -6,7 +6,7 @@ """ -def solution(n: int = 1000) -> int: +def solution(n): """Returns the sum of all the multiples of 3 or 5 below n. >>> solution(3) diff --git a/project_euler/problem_02/sol1.py b/project_euler/problem_02/sol1.py index 2acc93b0affc..ec89ddaeb2b5 100644 --- a/project_euler/problem_02/sol1.py +++ b/project_euler/problem_02/sol1.py @@ -11,7 +11,7 @@ """ -def solution(n: int = 4000000) -> int: +def solution(n): """Returns the sum of all fibonacci sequence even elements that are lower or equals to n. @@ -28,13 +28,13 @@ def solution(n: int = 4000000) -> int: """ i = 1 j = 2 - total = 0 + sum = 0 while j <= n: if j % 2 == 0: - total += j + sum += j i, j = j, i + j - return total + return sum if __name__ == "__main__": diff --git a/project_euler/problem_02/sol2.py b/project_euler/problem_02/sol2.py index 01fc552b9b21..bc5040cc6b3b 100644 --- a/project_euler/problem_02/sol2.py +++ b/project_euler/problem_02/sol2.py @@ -11,28 +11,28 @@ """ -def solution(n: int = 4000000) -> int: +def solution(n): """Returns the sum of all fibonacci sequence even elements that are lower or equals to n. >>> solution(10) - 10 + [2, 8] >>> solution(15) - 10 + [2, 8] >>> solution(2) - 2 + [2] >>> solution(1) - 0 + [] >>> solution(34) - 44 + [2, 8, 34] """ - even_fibs = [] + ls = [] a, b = 0, 1 while b <= n: if b % 2 == 0: - even_fibs.append(b) + ls.append(b) a, b = b, a + b - return sum(even_fibs) + return ls if __name__ == "__main__": diff --git a/project_euler/problem_02/sol3.py b/project_euler/problem_02/sol3.py index 53d8ca6f1b68..f29f21c287e5 100644 --- a/project_euler/problem_02/sol3.py +++ b/project_euler/problem_02/sol3.py @@ -11,7 +11,7 @@ """ -def solution(n: int = 4000000) -> int: +def solution(n): """Returns the sum of all fibonacci sequence even elements that are lower or equals to n. diff --git a/project_euler/problem_02/sol4.py b/project_euler/problem_02/sol4.py index a87410b7006d..be4328941aa3 100644 --- a/project_euler/problem_02/sol4.py +++ b/project_euler/problem_02/sol4.py @@ -13,7 +13,7 @@ from decimal import Decimal, getcontext -def solution(n: int = 4000000) -> int: +def solution(n): """Returns the sum of all fibonacci sequence even elements that are lower or equals to n. @@ -57,8 +57,8 @@ def solution(n: int = 4000000) -> int: index = (math.floor(math.log(n * (phi + 2), phi) - 1) // 3) * 3 + 2 num = Decimal(round(phi ** Decimal(index + 1))) / (phi + 2) - total = num // 2 - return int(total) + sum = num // 2 + return int(sum) if __name__ == "__main__": diff --git a/project_euler/problem_02/sol5.py b/project_euler/problem_02/sol5.py index dcf6eae85891..180906cf8717 100644 --- a/project_euler/problem_02/sol5.py +++ b/project_euler/problem_02/sol5.py @@ -11,7 +11,7 @@ """ -def solution(n: int = 4000000) -> int: +def solution(n): """Returns the sum of all fibonacci sequence even elements that are lower or equals to n. @@ -27,19 +27,19 @@ def solution(n: int = 4000000) -> int: 44 """ - fib = [0, 1] + a = [0, 1] i = 0 - while fib[i] <= n: - fib.append(fib[i] + fib[i + 1]) - if fib[i + 2] > n: + while a[i] <= n: + a.append(a[i] + a[i + 1]) + if a[i + 2] > n: break i += 1 - total = 0 - for j in range(len(fib) - 1): - if fib[j] % 2 == 0: - total += fib[j] + sum = 0 + for j in range(len(a) - 1): + if a[j] % 2 == 0: + sum += a[j] - return total + return sum if __name__ == "__main__": diff --git a/project_euler/problem_03/sol1.py b/project_euler/problem_03/sol1.py index 22efeb2c4e90..347f8a53f5b4 100644 --- a/project_euler/problem_03/sol1.py +++ b/project_euler/problem_03/sol1.py @@ -5,43 +5,24 @@ e.g. for 10, largest prime factor = 5. For 17, largest prime factor = 17. """ - import math -def isprime(num: int) -> bool: - """Returns boolean representing primality of given number num. - >>> isprime(2) - True - >>> isprime(3) - True - >>> isprime(27) - False - >>> isprime(2999) - True - >>> isprime(0) - Traceback (most recent call last): - ... - ValueError: Parameter num must be greater or equal to two. - >>> isprime(1) - Traceback (most recent call last): - ... - ValueError: Parameter num must be greater or equal to two. - """ - if num <= 1: - raise ValueError("Parameter num must be greater or equal to two.") - if num == 2: +def isprime(no): + if no == 2: return True - elif num % 2 == 0: + elif no % 2 == 0: return False - for i in range(3, int(math.sqrt(num)) + 1, 2): - if num % i == 0: + sq = int(math.sqrt(no)) + 1 + for i in range(3, sq, 2): + if no % i == 0: return False return True -def solution(n: int = 600851475143) -> int: +def solution(n): """Returns the largest prime factor of a given number n. + >>> solution(13195) 29 >>> solution(10) @@ -73,21 +54,24 @@ def solution(n: int = 600851475143) -> int: raise TypeError("Parameter n must be int or passive of cast to int.") if n <= 0: raise ValueError("Parameter n must be greater or equal to one.") - max_number = 0 - if isprime(n): - return n - while n % 2 == 0: - n //= 2 + maxNumber = 0 if isprime(n): return n - for i in range(3, int(math.sqrt(n)) + 1, 2): - if n % i == 0: - if isprime(n / i): - max_number = n / i - break - elif isprime(i): - max_number = i - return max_number + else: + while n % 2 == 0: + n = n / 2 + if isprime(n): + return int(n) + else: + n1 = int(math.sqrt(n)) + 1 + for i in range(3, n1, 2): + if n % i == 0: + if isprime(n / i): + maxNumber = n / i + break + elif isprime(i): + maxNumber = i + return maxNumber if __name__ == "__main__": diff --git a/project_euler/problem_03/sol2.py b/project_euler/problem_03/sol2.py index f28232109a84..daac041d4bd9 100644 --- a/project_euler/problem_03/sol2.py +++ b/project_euler/problem_03/sol2.py @@ -7,8 +7,9 @@ """ -def solution(n: int = 600851475143) -> int: +def solution(n): """Returns the largest prime factor of a given number n. + >>> solution(13195) 29 >>> solution(10) diff --git a/project_euler/problem_03/sol3.py b/project_euler/problem_03/sol3.py index 676717cceca8..5fe45df59984 100644 --- a/project_euler/problem_03/sol3.py +++ b/project_euler/problem_03/sol3.py @@ -7,8 +7,9 @@ """ -def solution(n: int = 600851475143) -> int: +def solution(n: int) -> int: """Returns the largest prime factor of a given number n. + >>> solution(13195) 29 >>> solution(10) @@ -51,8 +52,12 @@ def solution(n: int = 600851475143) -> int: while n % i == 0: n = n / i i += 1 + return int(ans) if __name__ == "__main__": - print(solution(int(input().strip()))) + # print(solution(int(input().strip()))) + import doctest + + doctest.testmod() diff --git a/project_euler/problem_04/sol1.py b/project_euler/problem_04/sol1.py index 42f56f3ef389..227b594d0df7 100644 --- a/project_euler/problem_04/sol1.py +++ b/project_euler/problem_04/sol1.py @@ -8,7 +8,7 @@ """ -def solution(n: int = 998001) -> int: +def solution(n): """Returns the largest palindrome made from the product of two 3-digit numbers which is less than n. diff --git a/project_euler/problem_04/sol2.py b/project_euler/problem_04/sol2.py index 8ee082ad2f6a..0f185f1216ab 100644 --- a/project_euler/problem_04/sol2.py +++ b/project_euler/problem_04/sol2.py @@ -8,7 +8,7 @@ """ -def solution(n: int = 998001) -> int: +def solution(n): """Returns the largest palindrome made from the product of two 3-digit numbers which is less than n. @@ -22,8 +22,8 @@ def solution(n: int = 998001) -> int: answer = 0 for i in range(999, 99, -1): # 3 digit numbers range from 999 down to 100 for j in range(999, 99, -1): - product_string = str(i * j) - if product_string == product_string[::-1] and i * j < n: + t = str(i * j) + if t == t[::-1] and i * j < n: answer = max(answer, i * j) return answer diff --git a/project_euler/problem_06/sol1.py b/project_euler/problem_06/sol1.py index 38f995bbf822..d6506ea2839c 100644 --- a/project_euler/problem_06/sol1.py +++ b/project_euler/problem_06/sol1.py @@ -1,5 +1,5 @@ """ -Problem 6: https://projecteuler.net/problem=6 +Problem: The sum of the squares of the first ten natural numbers is, 1^2 + 2^2 + ... + 10^2 = 385 @@ -15,7 +15,7 @@ """ -def solution(n: int = 100) -> int: +def solution(n: int) -> int: """Returns the difference between the sum of the squares of the first n natural numbers and the square of the sum. @@ -27,8 +27,6 @@ def solution(n: int = 100) -> int: 41230 >>> solution(50) 1582700 - >>> solution() - 25164150 """ sum_of_squares = 0 sum_of_ints = 0 diff --git a/project_euler/problem_06/sol2.py b/project_euler/problem_06/sol2.py index f4d74c993f0d..5032775f9f77 100644 --- a/project_euler/problem_06/sol2.py +++ b/project_euler/problem_06/sol2.py @@ -1,5 +1,5 @@ """ -Problem 6: https://projecteuler.net/problem=6 +Problem: The sum of the squares of the first ten natural numbers is, 1^2 + 2^2 + ... + 10^2 = 385 @@ -15,7 +15,7 @@ """ -def solution(n: int = 100) -> int: +def solution(n: int) -> int: """Returns the difference between the sum of the squares of the first n natural numbers and the square of the sum. @@ -27,8 +27,6 @@ def solution(n: int = 100) -> int: 41230 >>> solution(50) 1582700 - >>> solution() - 25164150 """ sum_cubes = (n * (n + 1) // 2) ** 2 sum_squares = n * (n + 1) * (2 * n + 1) // 6 diff --git a/project_euler/problem_06/sol3.py b/project_euler/problem_06/sol3.py index 8b5c5d3ba4aa..385ad05151fb 100644 --- a/project_euler/problem_06/sol3.py +++ b/project_euler/problem_06/sol3.py @@ -1,5 +1,5 @@ """ -Problem 6: https://projecteuler.net/problem=6 +Problem: The sum of the squares of the first ten natural numbers is, 1^2 + 2^2 + ... + 10^2 = 385 @@ -16,7 +16,7 @@ import math -def solution(n: int = 100) -> int: +def solution(n: int) -> int: """Returns the difference between the sum of the squares of the first n natural numbers and the square of the sum. @@ -28,8 +28,6 @@ def solution(n: int = 100) -> int: 41230 >>> solution(50) 1582700 - >>> solution() - 25164150 """ sum_of_squares = sum([i * i for i in range(1, n + 1)]) square_of_sum = int(math.pow(sum(range(1, n + 1)), 2)) diff --git a/project_euler/problem_06/sol4.py b/project_euler/problem_06/sol4.py index 5fae84008448..912a3e8f6096 100644 --- a/project_euler/problem_06/sol4.py +++ b/project_euler/problem_06/sol4.py @@ -1,5 +1,5 @@ """ -Problem 6: https://projecteuler.net/problem=6 +Problem: The sum of the squares of the first ten natural numbers is, 1^2 + 2^2 + ... + 10^2 = 385 @@ -15,7 +15,7 @@ """ -def solution(n: int = 100) -> int: +def solution(n: int) -> int: """Returns the difference between the sum of the squares of the first n natural numbers and the square of the sum. @@ -27,7 +27,7 @@ def solution(n: int = 100) -> int: 41230 >>> solution(50) 1582700 - >>> solution() + >>> solution(100) 25164150 """ sum_of_squares = n * (n + 1) * (2 * n + 1) / 6 diff --git a/project_euler/problem_06/test_solutions.py b/project_euler/problem_06/test_solutions.py new file mode 100644 index 000000000000..6d5337789655 --- /dev/null +++ b/project_euler/problem_06/test_solutions.py @@ -0,0 +1,18 @@ +from .sol1 import solution as sol1 +from .sol2 import solution as sol2 +from .sol3 import solution as sol3 +from .sol4 import solution as sol4 + + +def test_solutions() -> None: + """ + >>> test_solutions() + """ + assert sol1(10) == sol2(10) == sol3(10) == sol4(10) == 2640 + assert sol1(15) == sol2(15) == sol3(15) == sol4(15) == 13160 + assert sol1(20) == sol2(20) == sol3(20) == sol4(20) == 41230 + assert sol1(50) == sol2(50) == sol3(50) == sol4(50) == 1582700 + + +if __name__ == "__main__": + test_solutions() diff --git a/project_euler/problem_10/sol1.py b/project_euler/problem_10/sol1.py index 4f3b3a4a42f5..c81085951ecf 100644 --- a/project_euler/problem_10/sol1.py +++ b/project_euler/problem_10/sol1.py @@ -1,6 +1,4 @@ """ -https://projecteuler.net/problem=10 - Problem Statement: The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17. @@ -9,17 +7,7 @@ from math import sqrt -def is_prime(n: int) -> bool: - """Returns boolean representing primality of given number num. - >>> is_prime(2) - True - >>> is_prime(3) - True - >>> is_prime(27) - False - >>> is_prime(2999) - True - """ +def is_prime(n): for i in range(2, int(sqrt(n)) + 1): if n % i == 0: return False @@ -27,7 +15,20 @@ def is_prime(n: int) -> bool: return True -def solution(n: int = 2000000) -> int: +def sum_of_primes(n): + if n > 2: + sumOfPrimes = 2 + else: + return 0 + + for i in range(3, n, 2): + if is_prime(i): + sumOfPrimes += i + + return sumOfPrimes + + +def solution(n): """Returns the sum of all the primes below n. # The code below has been commented due to slow execution affecting Travis. @@ -42,16 +43,7 @@ def solution(n: int = 2000000) -> int: >>> solution(7) 10 """ - if n > 2: - sum_of_primes = 2 - else: - return 0 - - for i in range(3, n, 2): - if is_prime(i): - sum_of_primes += i - - return sum_of_primes + return sum_of_primes(n) if __name__ == "__main__": diff --git a/project_euler/problem_10/sol2.py b/project_euler/problem_10/sol2.py index 39f5f5604053..b2e2b6e1adf3 100644 --- a/project_euler/problem_10/sol2.py +++ b/project_euler/problem_10/sol2.py @@ -1,6 +1,4 @@ """ -https://projecteuler.net/problem=10 - Problem Statement: The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17. @@ -8,34 +6,23 @@ """ import math from itertools import takewhile -from typing import Iterator - - -def is_prime(number: int) -> bool: - """Returns boolean representing primality of given number num. - >>> is_prime(2) - True - >>> is_prime(3) - True - >>> is_prime(27) - False - >>> is_prime(2999) - True - """ + + +def primeCheck(number): if number % 2 == 0 and number > 2: return False return all(number % i for i in range(3, int(math.sqrt(number)) + 1, 2)) -def prime_generator() -> Iterator[int]: +def prime_generator(): num = 2 while True: - if is_prime(num): + if primeCheck(num): yield num num += 1 -def solution(n: int = 2000000) -> int: +def solution(n): """Returns the sum of all the primes below n. # The code below has been commented due to slow execution affecting Travis. diff --git a/project_euler/problem_10/sol3.py b/project_euler/problem_10/sol3.py index ef895f546fa5..739aaa9f16bb 100644 --- a/project_euler/problem_10/sol3.py +++ b/project_euler/problem_10/sol3.py @@ -4,54 +4,55 @@ Problem Statement: The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17. -Find the sum of all the primes below two million. -""" +Find the sum of all the primes below two million using Sieve_of_Eratosthenes: +The sieve of Eratosthenes is one of the most efficient ways to find all primes +smaller than n when n is smaller than 10 million. Only for positive numbers. +""" -def solution(n: int = 2000000) -> int: - """Returns the sum of all the primes below n using Sieve of Eratosthenes: - https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes - The sieve of Eratosthenes is one of the most efficient ways to find all primes - smaller than n when n is smaller than 10 million. Only for positive numbers. +def prime_sum(n: int) -> int: + """Returns the sum of all the primes below n. - >>> solution(2_000_000) + >>> prime_sum(2_000_000) 142913828922 - >>> solution(1_000) + >>> prime_sum(1_000) 76127 - >>> solution(5_000) + >>> prime_sum(5_000) 1548136 - >>> solution(10_000) + >>> prime_sum(10_000) 5736396 - >>> solution(7) + >>> prime_sum(7) 10 - >>> solution(7.1) # doctest: +ELLIPSIS + >>> prime_sum(7.1) # doctest: +ELLIPSIS Traceback (most recent call last): ... TypeError: 'float' object cannot be interpreted as an integer - >>> solution(-7) # doctest: +ELLIPSIS + >>> prime_sum(-7) # doctest: +ELLIPSIS Traceback (most recent call last): ... IndexError: list assignment index out of range - >>> solution("seven") # doctest: +ELLIPSIS + >>> prime_sum("seven") # doctest: +ELLIPSIS Traceback (most recent call last): ... TypeError: can only concatenate str (not "int") to str """ - primality_list = [0 for i in range(n + 1)] - primality_list[0] = 1 - primality_list[1] = 1 + list_ = [0 for i in range(n + 1)] + list_[0] = 1 + list_[1] = 1 for i in range(2, int(n ** 0.5) + 1): - if primality_list[i] == 0: + if list_[i] == 0: for j in range(i * i, n + 1, i): - primality_list[j] = 1 - sum_of_primes = 0 + list_[j] = 1 + s = 0 for i in range(n): - if primality_list[i] == 0: - sum_of_primes += i - return sum_of_primes + if list_[i] == 0: + s += i + return s if __name__ == "__main__": - print(solution(int(input().strip()))) + # import doctest + # doctest.testmod() + print(prime_sum(int(input().strip()))) diff --git a/project_euler/problem_120/__init__.py b/project_euler/problem_120/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/project_euler/problem_120/sol1.py b/project_euler/problem_120/sol1.py deleted file mode 100644 index 0e6821214560..000000000000 --- a/project_euler/problem_120/sol1.py +++ /dev/null @@ -1,32 +0,0 @@ -""" -Problem 120 Square remainders: https://projecteuler.net/problem=120 - -Description: - -Let r be the remainder when (a−1)^n + (a+1)^n is divided by a^2. -For example, if a = 7 and n = 3, then r = 42: 6^3 + 8^3 = 728 ≡ 42 mod 49. -And as n varies, so too will r, but for a = 7 it turns out that r_max = 42. -For 3 ≤ a ≤ 1000, find ∑ r_max. - -Solution: - -On expanding the terms, we get 2 if n is even and 2an if n is odd. -For maximizing the value, 2an < a*a => n <= (a - 1)/2 (integer division) -""" - - -def solution(n: int = 1000) -> int: - """ - Returns ∑ r_max for 3 <= a <= n as explained above - >>> solution(10) - 300 - >>> solution(100) - 330750 - >>> solution(1000) - 333082500 - """ - return sum(2 * a * ((a - 1) // 2) for a in range(3, n + 1)) - - -if __name__ == "__main__": - print(solution()) diff --git a/project_euler/problem_20/sol1.py b/project_euler/problem_20/sol1.py index b472024e54c0..13b3c987f046 100644 --- a/project_euler/problem_20/sol1.py +++ b/project_euler/problem_20/sol1.py @@ -1,6 +1,4 @@ """ -Problem 20: https://projecteuler.net/problem=20 - n! means n × (n − 1) × ... × 3 × 2 × 1 For example, 10! = 10 × 9 × ... × 3 × 2 × 1 = 3628800, @@ -10,15 +8,14 @@ """ -def factorial(num: int) -> int: - """Find the factorial of a given number n""" +def factorial(n): fact = 1 - for i in range(1, num + 1): + for i in range(1, n + 1): fact *= i return fact -def split_and_add(number: int) -> int: +def split_and_add(number): """Split number digits and add them.""" sum_of_digits = 0 while number > 0: @@ -28,8 +25,8 @@ def split_and_add(number: int) -> int: return sum_of_digits -def solution(num: int = 100) -> int: - """Returns the sum of the digits in the factorial of num +def solution(n): + """Returns the sum of the digits in the number 100! >>> solution(100) 648 >>> solution(50) @@ -45,8 +42,8 @@ def solution(num: int = 100) -> int: >>> solution(1) 1 """ - nfact = factorial(num) - result = split_and_add(nfact) + f = factorial(n) + result = split_and_add(f) return result diff --git a/project_euler/problem_20/sol2.py b/project_euler/problem_20/sol2.py index 92e1e724a647..14e591795292 100644 --- a/project_euler/problem_20/sol2.py +++ b/project_euler/problem_20/sol2.py @@ -1,6 +1,4 @@ """ -Problem 20: https://projecteuler.net/problem=20 - n! means n × (n − 1) × ... × 3 × 2 × 1 For example, 10! = 10 × 9 × ... × 3 × 2 × 1 = 3628800, @@ -11,8 +9,8 @@ from math import factorial -def solution(num: int = 100) -> int: - """Returns the sum of the digits in the factorial of num +def solution(n): + """Returns the sum of the digits in the number 100! >>> solution(100) 648 >>> solution(50) @@ -28,7 +26,7 @@ def solution(num: int = 100) -> int: >>> solution(1) 1 """ - return sum([int(x) for x in str(factorial(num))]) + return sum([int(x) for x in str(factorial(n))]) if __name__ == "__main__": diff --git a/project_euler/problem_20/sol3.py b/project_euler/problem_20/sol3.py index 4f28ac5fcfde..13f9d7831c47 100644 --- a/project_euler/problem_20/sol3.py +++ b/project_euler/problem_20/sol3.py @@ -1,6 +1,4 @@ """ -Problem 20: https://projecteuler.net/problem=20 - n! means n × (n − 1) × ... × 3 × 2 × 1 For example, 10! = 10 × 9 × ... × 3 × 2 × 1 = 3628800, @@ -11,8 +9,8 @@ from math import factorial -def solution(num: int = 100) -> int: - """Returns the sum of the digits in the factorial of num +def solution(n): + """Returns the sum of the digits in the number 100! >>> solution(1000) 10539 >>> solution(200) @@ -34,7 +32,7 @@ def solution(num: int = 100) -> int: >>> solution(0) 1 """ - return sum(map(int, str(factorial(num)))) + return sum(map(int, str(factorial(n)))) if __name__ == "__main__": diff --git a/project_euler/problem_20/sol4.py b/project_euler/problem_20/sol4.py index b32ce309dfa6..4c597220f09b 100644 --- a/project_euler/problem_20/sol4.py +++ b/project_euler/problem_20/sol4.py @@ -1,6 +1,4 @@ """ -Problem 20: https://projecteuler.net/problem=20 - n! means n × (n − 1) × ... × 3 × 2 × 1 For example, 10! = 10 × 9 × ... × 3 × 2 × 1 = 3628800, @@ -10,8 +8,8 @@ """ -def solution(num: int = 100) -> int: - """Returns the sum of the digits in the factorial of num +def solution(n): + """Returns the sum of the digits in the number 100! >>> solution(100) 648 >>> solution(50) @@ -29,7 +27,7 @@ def solution(num: int = 100) -> int: """ fact = 1 result = 0 - for i in range(1, num + 1): + for i in range(1, n + 1): fact *= i for j in str(fact): diff --git a/project_euler/problem_25/sol1.py b/project_euler/problem_25/sol1.py index c30a74a43cb0..f0228915dc15 100644 --- a/project_euler/problem_25/sol1.py +++ b/project_euler/problem_25/sol1.py @@ -25,24 +25,7 @@ """ -def fibonacci(n: int) -> int: - """ - Computes the Fibonacci number for input n by iterating through n numbers - and creating an array of ints using the Fibonacci formula. - Returns the nth element of the array. - - >>> fibonacci(2) - 1 - >>> fibonacci(3) - 2 - >>> fibonacci(5) - 5 - >>> fibonacci(10) - 55 - >>> fibonacci(12) - 144 - - """ +def fibonacci(n): if n == 1 or type(n) is not int: return 0 elif n == 2: @@ -55,21 +38,7 @@ def fibonacci(n: int) -> int: return sequence[n] -def fibonacci_digits_index(n: int) -> int: - """ - Computes incrementing Fibonacci numbers starting from 3 until the length - of the resulting Fibonacci result is the input value n. Returns the term - of the Fibonacci sequence where this occurs. - - >>> fibonacci_digits_index(1000) - 4782 - >>> fibonacci_digits_index(100) - 476 - >>> fibonacci_digits_index(50) - 237 - >>> fibonacci_digits_index(3) - 12 - """ +def fibonacci_digits_index(n): digits = 0 index = 2 @@ -80,9 +49,8 @@ def fibonacci_digits_index(n: int) -> int: return index -def solution(n: int = 1000) -> int: - """ - Returns the index of the first term in the Fibonacci sequence to contain +def solution(n): + """Returns the index of the first term in the Fibonacci sequence to contain n digits. >>> solution(1000) diff --git a/project_euler/problem_25/sol2.py b/project_euler/problem_25/sol2.py index ed3b54bb351f..c98f09b1d316 100644 --- a/project_euler/problem_25/sol2.py +++ b/project_euler/problem_25/sol2.py @@ -25,29 +25,14 @@ """ -def fibonacci_generator() -> int: - """ - A generator that produces numbers in the Fibonacci sequence - - >>> generator = fibonacci_generator() - >>> next(generator) - 1 - >>> next(generator) - 2 - >>> next(generator) - 3 - >>> next(generator) - 5 - >>> next(generator) - 8 - """ +def fibonacci_generator(): a, b = 0, 1 while True: a, b = b, a + b yield b -def solution(n: int = 1000) -> int: +def solution(n): """Returns the index of the first term in the Fibonacci sequence to contain n digits. diff --git a/project_euler/problem_25/sol3.py b/project_euler/problem_25/sol3.py index c66411dc55fc..4a1d9da76bf7 100644 --- a/project_euler/problem_25/sol3.py +++ b/project_euler/problem_25/sol3.py @@ -25,7 +25,7 @@ """ -def solution(n: int = 1000) -> int: +def solution(n): """Returns the index of the first term in the Fibonacci sequence to contain n digits. diff --git a/project_euler/problem_28/sol1.py b/project_euler/problem_28/sol1.py index cbc7de6bea9a..11b48fea9adf 100644 --- a/project_euler/problem_28/sol1.py +++ b/project_euler/problem_28/sol1.py @@ -1,7 +1,4 @@ """ -Problem 28 -Url: https://projecteuler.net/problem=28 -Statement: Starting with the number 1 and moving to the right in a clockwise direction a 5 by 5 spiral is formed as follows: @@ -20,19 +17,19 @@ from math import ceil -def solution(n: int = 1001) -> int: +def diagonal_sum(n): """Returns the sum of the numbers on the diagonals in a n by n spiral formed in the same way. - >>> solution(1001) + >>> diagonal_sum(1001) 669171001 - >>> solution(500) + >>> diagonal_sum(500) 82959497 - >>> solution(100) + >>> diagonal_sum(100) 651897 - >>> solution(50) + >>> diagonal_sum(50) 79697 - >>> solution(10) + >>> diagonal_sum(10) 537 """ total = 1 @@ -49,10 +46,10 @@ def solution(n: int = 1001) -> int: import sys if len(sys.argv) == 1: - print(solution()) + print(diagonal_sum(1001)) else: try: n = int(sys.argv[1]) - print(solution(n)) + print(diagonal_sum(n)) except ValueError: print("Invalid entry - please enter a number") diff --git a/project_euler/problem_29/sol1.py b/project_euler/problem_29/solution.py similarity index 97% rename from project_euler/problem_29/sol1.py rename to project_euler/problem_29/solution.py index 726bcaf6ebd8..4313a7b06392 100644 --- a/project_euler/problem_29/sol1.py +++ b/project_euler/problem_29/solution.py @@ -16,7 +16,7 @@ """ -def solution(n: int = 100) -> int: +def solution(n): """Returns the number of distinct terms in the sequence generated by a^b for 2 <= a <= 100 and 2 <= b <= 100. diff --git a/project_euler/problem_30/sol1.py b/project_euler/problem_30/soln.py similarity index 89% rename from project_euler/problem_30/sol1.py rename to project_euler/problem_30/soln.py index c9f2d71965e3..3ade82208344 100644 --- a/project_euler/problem_30/sol1.py +++ b/project_euler/problem_30/soln.py @@ -31,9 +31,6 @@ def digitsum(s: str) -> int: return i if i == int(s) else 0 -def solution() -> int: - return sum(digitsum(str(i)) for i in range(1000, 1000000)) - - if __name__ == "__main__": - print(solution()) + count = sum(digitsum(str(i)) for i in range(1000, 1000000)) + print(count) # --> 443839 diff --git a/project_euler/problem_49/__init__.py b/project_euler/problem_49/__init__.py deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/project_euler/problem_49/sol1.py b/project_euler/problem_49/sol1.py deleted file mode 100644 index 6c3d69ad0d11..000000000000 --- a/project_euler/problem_49/sol1.py +++ /dev/null @@ -1,139 +0,0 @@ -""" -Prime permutations - -Problem 49 - -The arithmetic sequence, 1487, 4817, 8147, in which each of -the terms increases by 3330, is unusual in two ways: -(i) each of the three terms are prime, -(ii) each of the 4-digit numbers are permutations of one another. - -There are no arithmetic sequences made up of three 1-, 2-, or 3-digit primes, -exhibiting this property, but there is one other 4-digit increasing sequence. - -What 12-digit number do you form by concatenating the three terms in this sequence? - -Solution: - -First, we need to generate all 4 digits prime numbers. Then greedy -all of them and use permutation to form new numbers. Use binary search -to check if the permutated numbers is in our prime list and include -them in a candidate list. - -After that, bruteforce all passed candidates sequences using -3 nested loops since we know the answer will be 12 digits. -The bruteforce of this solution will be about 1 sec. -""" - -from itertools import permutations -from math import floor, sqrt - - -def is_prime(number: int) -> bool: - """ - function to check whether the number is prime or not. - >>> is_prime(2) - True - >>> is_prime(6) - False - >>> is_prime(1) - False - >>> is_prime(-800) - False - >>> is_prime(104729) - True - """ - - if number < 2: - return False - - for i in range(2, floor(sqrt(number)) + 1): - if number % i == 0: - return False - - return True - - -def search(target: int, prime_list: list) -> bool: - """ - function to search a number in a list using Binary Search. - >>> search(3, [1, 2, 3]) - True - >>> search(4, [1, 2, 3]) - False - >>> search(101, list(range(-100, 100))) - False - """ - - left, right = 0, len(prime_list) - 1 - while left <= right: - middle = (left + right) // 2 - if prime_list[middle] == target: - return True - elif prime_list[middle] < target: - left = middle + 1 - else: - right = middle - 1 - - return False - - -def solution(): - """ - Return the solution of the problem. - >>> solution() - 296962999629 - """ - prime_list = [n for n in range(1001, 10000, 2) if is_prime(n)] - candidates = [] - - for number in prime_list: - tmp_numbers = [] - - for prime_member in permutations(list(str(number))): - prime = int("".join(prime_member)) - - if prime % 2 == 0: - continue - - if search(prime, prime_list): - tmp_numbers.append(prime) - - tmp_numbers.sort() - if len(tmp_numbers) >= 3: - candidates.append(tmp_numbers) - - passed = [] - for candidate in candidates: - length = len(candidate) - found = False - - for i in range(length): - for j in range(i + 1, length): - for k in range(j + 1, length): - if ( - abs(candidate[i] - candidate[j]) - == abs(candidate[j] - candidate[k]) - and len(set([candidate[i], candidate[j], candidate[k]])) == 3 - ): - passed.append( - sorted([candidate[i], candidate[j], candidate[k]]) - ) - found = True - - if found: - break - if found: - break - if found: - break - - answer = set() - for seq in passed: - answer.add("".join([str(i) for i in seq])) - - return max([int(x) for x in answer]) - - -if __name__ == "__main__": - print(solution()) diff --git a/project_euler/problem_55/sol1.py b/project_euler/problem_55/sol1.py index 14e411541f3a..a2e27bbb9e93 100644 --- a/project_euler/problem_55/sol1.py +++ b/project_euler/problem_55/sol1.py @@ -1,15 +1,10 @@ """ -Lychrel numbers -Problem 55: https://projecteuler.net/problem=55 - If we take 47, reverse and add, 47 + 74 = 121, which is palindromic. - Not all numbers produce palindromes so quickly. For example, 349 + 943 = 1292, 1292 + 2921 = 4213 4213 + 3124 = 7337 That is, 349 took three iterations to arrive at a palindrome. - Although no one has proved it yet, it is thought that some numbers, like 196, never produce a palindrome. A number that never forms a palindrome through the reverse and add process is called a Lychrel number. Due to the theoretical nature @@ -53,14 +48,14 @@ def sum_reverse(n: int) -> int: return int(n) + int(str(n)[::-1]) -def solution(limit: int = 10000) -> int: +def compute_lychrel_nums(limit: int) -> int: """ Returns the count of all lychrel numbers below limit. - >>> solution(10000) + >>> compute_lychrel_nums(10000) 249 - >>> solution(5000) + >>> compute_lychrel_nums(5000) 76 - >>> solution(1000) + >>> compute_lychrel_nums(1000) 13 """ lychrel_nums = [] @@ -78,4 +73,4 @@ def solution(limit: int = 10000) -> int: if __name__ == "__main__": - print(f"{solution() = }") + print(f"{compute_lychrel_nums(10000) = }") diff --git a/project_euler/problem_76/sol1.py b/project_euler/problem_76/sol1.py index 60bb87089e7e..ed0ee6b507e9 100644 --- a/project_euler/problem_76/sol1.py +++ b/project_euler/problem_76/sol1.py @@ -1,6 +1,6 @@ """ Counting Summations -Problem 76: https://projecteuler.net/problem=76 +Problem 76 It is possible to write five as a sum in exactly six different ways: @@ -16,26 +16,25 @@ """ -def solution(m: int = 100) -> int: - """ - Returns the number of different ways the number m can be written as a - sum of at least two positive integers. +def partition(m): + """Returns the number of different ways one hundred can be written as a sum + of at least two positive integers. - >>> solution(100) + >>> partition(100) 190569291 - >>> solution(50) + >>> partition(50) 204225 - >>> solution(30) + >>> partition(30) 5603 - >>> solution(10) + >>> partition(10) 41 - >>> solution(5) + >>> partition(5) 6 - >>> solution(3) + >>> partition(3) 2 - >>> solution(2) + >>> partition(2) 1 - >>> solution(1) + >>> partition(1) 0 """ memo = [[0 for _ in range(m)] for _ in range(m + 1)] @@ -52,4 +51,4 @@ def solution(m: int = 100) -> int: if __name__ == "__main__": - print(solution(int(input("Enter a number: ").strip()))) + print(partition(int(str(input()).strip()))) diff --git a/project_euler/problem_99/sol1.py b/project_euler/problem_99/sol1.py index 88912e1f0f9e..0148a80ef481 100644 --- a/project_euler/problem_99/sol1.py +++ b/project_euler/problem_99/sol1.py @@ -17,9 +17,9 @@ from math import log10 -def solution(data_file: str = "base_exp.txt") -> int: +def find_largest(data_file: str = "base_exp.txt") -> int: """ - >>> solution() + >>> find_largest() 709 """ largest = [0, 0] @@ -31,4 +31,4 @@ def solution(data_file: str = "base_exp.txt") -> int: if __name__ == "__main__": - print(solution()) + print(find_largest()) diff --git a/searches/simple_binary_search.py b/searches/simple_binary_search.py index d1f7f7a51cbc..8495dda8d518 100644 --- a/searches/simple_binary_search.py +++ b/searches/simple_binary_search.py @@ -31,14 +31,8 @@ def binary_search(a_list: list[int], item: int) -> bool: False >>> print(binary_search([], 1)) False - >>> print(binary_search([-.1, .1 , .8], .1)) + >>> print(binary_search([.1, .4 , -.1], .1)) True - >>> binary_search(range(-5000, 5000, 10), 80) - True - >>> binary_search(range(-5000, 5000, 10), 1255) - False - >>> binary_search(range(0, 10000, 5), 2) - False """ if len(a_list) == 0: return False diff --git a/searches/ternary_search.py b/searches/ternary_search.py index b01db3eb845f..6fdee58cf5dc 100644 --- a/searches/ternary_search.py +++ b/searches/ternary_search.py @@ -7,7 +7,6 @@ Space Complexity : O(1) """ import sys -from typing import List # This is the precision for this function which can be altered. # It is recommended for users to keep this number greater than or equal to 10. @@ -15,14 +14,14 @@ # This is the linear search that will occur after the search space has become smaller. -def lin_search(left: int, right: int, A: List[int], target: int): +def lin_search(left, right, A, target): for i in range(left, right + 1): if A[i] == target: return i # This is the iterative method of the ternary search algorithm. -def ite_ternary_search(A: List[int], target: int): +def ite_ternary_search(A, target): left = 0 right = len(A) - 1 while True: @@ -52,7 +51,7 @@ def ite_ternary_search(A: List[int], target: int): # This is the recursive method of the ternary search algorithm. -def rec_ternary_search(left: int, right: int, A: List[int], target: int): +def rec_ternary_search(left, right, A, target): if left < right: if right - left < precision: @@ -78,7 +77,7 @@ def rec_ternary_search(left: int, right: int, A: List[int], target: int): # This function is to check if the array is sorted. -def __assert_sorted(collection: List[int]) -> bool: +def __assert_sorted(collection): if collection != sorted(collection): raise ValueError("Collection must be sorted") return True diff --git a/strings/aho_corasick.py b/strings/aho_corasick.py index b959dbd58c32..bb6955bdd423 100644 --- a/strings/aho_corasick.py +++ b/strings/aho_corasick.py @@ -1,9 +1,8 @@ from collections import deque -from typing import Dict, List, Union class Automaton: - def __init__(self, keywords: List[str]): + def __init__(self, keywords): self.adlist = list() self.adlist.append( {"value": "", "next_states": [], "fail_state": 0, "output": []} @@ -13,13 +12,13 @@ def __init__(self, keywords: List[str]): self.add_keyword(keyword) self.set_fail_transitions() - def find_next_state(self, current_state: int, char: str) -> Union[int, None]: + def find_next_state(self, current_state, char): for state in self.adlist[current_state]["next_states"]: if char == self.adlist[state]["value"]: return state return None - def add_keyword(self, keyword: str) -> None: + def add_keyword(self, keyword): current_state = 0 for character in keyword: if self.find_next_state(current_state, character): @@ -37,7 +36,7 @@ def add_keyword(self, keyword: str) -> None: current_state = len(self.adlist) - 1 self.adlist[current_state]["output"].append(keyword) - def set_fail_transitions(self) -> None: + def set_fail_transitions(self): q = deque() for node in self.adlist[0]["next_states"]: q.append(node) @@ -62,7 +61,7 @@ def set_fail_transitions(self) -> None: + self.adlist[self.adlist[child]["fail_state"]]["output"] ) - def search_in(self, string: str) -> Dict[str, List[int]]: + def search_in(self, string): """ >>> A = Automaton(["what", "hat", "ver", "er"]) >>> A.search_in("whatever, err ... , wherever") diff --git a/strings/boyer_moore_search.py b/strings/boyer_moore_search.py index a3e6cf614eab..9d32a6943906 100644 --- a/strings/boyer_moore_search.py +++ b/strings/boyer_moore_search.py @@ -17,15 +17,14 @@ n=length of main string m=length of pattern string """ -from typing import List class BoyerMooreSearch: - def __init__(self, text: str, pattern: str): + def __init__(self, text, pattern): self.text, self.pattern = text, pattern self.textLen, self.patLen = len(text), len(pattern) - def match_in_pattern(self, char: str) -> int: + def match_in_pattern(self, char): """finds the index of char in pattern in reverse order Parameters : @@ -41,7 +40,7 @@ def match_in_pattern(self, char: str) -> int: return i return -1 - def mismatch_in_text(self, currentPos: int) -> int: + def mismatch_in_text(self, currentPos): """ find the index of mis-matched character in text when compared with pattern from last @@ -59,7 +58,7 @@ def mismatch_in_text(self, currentPos: int) -> int: return currentPos + i return -1 - def bad_character_heuristic(self) -> List[int]: + def bad_character_heuristic(self): # searches pattern in text and returns index positions positions = [] for i in range(self.textLen - self.patLen + 1): diff --git a/strings/knuth_morris_pratt.py b/strings/knuth_morris_pratt.py index a205ce37e3e5..2e5e0c7e73f1 100644 --- a/strings/knuth_morris_pratt.py +++ b/strings/knuth_morris_pratt.py @@ -1,7 +1,4 @@ -from typing import List - - -def kmp(pattern: str, text: str) -> bool: +def kmp(pattern, text): """ The Knuth-Morris-Pratt Algorithm for finding a pattern within a piece of text with complexity O(n + m) @@ -36,7 +33,7 @@ def kmp(pattern: str, text: str) -> bool: return False -def get_failure_array(pattern: str) -> List[int]: +def get_failure_array(pattern): """ Calculates the new index we should go to if we fail a comparison :param pattern: diff --git a/strings/levenshtein_distance.py b/strings/levenshtein_distance.py index 54948a96670b..9b8793544a99 100644 --- a/strings/levenshtein_distance.py +++ b/strings/levenshtein_distance.py @@ -13,7 +13,7 @@ """ -def levenshtein_distance(first_word: str, second_word: str) -> int: +def levenshtein_distance(first_word, second_word): """Implementation of the levenshtein distance in Python. :param first_word: the first word to measure the difference. :param second_word: the second word to measure the difference. diff --git a/strings/lower.py b/strings/lower.py index b7abe9fc957d..27e7c4837bde 100644 --- a/strings/lower.py +++ b/strings/lower.py @@ -1,26 +1,31 @@ -def lower(word: str) -> str: +import unittest + +CAPITALS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + + +def lower_char(capital: str) -> str: """ - Will convert the entire string to lowecase letters - - >>> lower("wow") - 'wow' - >>> lower("HellZo") - 'hellzo' - >>> lower("WHAT") - 'what' - >>> lower("wh[]32") - 'wh[]32' - >>> lower("whAT") - 'what' + Convert a capital to a lowercase letter """ + # int value of lowercase char = int value of uppercase char + 32 + return chr(ord(capital) + 32) - # converting to ascii value int value and checking to see if char is a capital - # letter if it is a capital letter it is getting shift by 32 which makes it a lower - # case letter - return "".join(chr(ord(char) + 32) if "A" <= char <= "Z" else char for char in word) +def lower(string: str) -> str: + """ + Convert string to lowercase + """ + return "".join(lower_char(char) if char in CAPITALS else char for char in string) -if __name__ == "__main__": - from doctest import testmod - testmod() +class TestLower(unittest.TestCase): + def test_lower(self): + self.assertEqual(lower("wow"), "wow") + self.assertEqual(lower("HellZo"), "hellzo") + self.assertEqual(lower("WHAT"), "what") + self.assertEqual(lower("wh[]32"), "wh[]32") + self.assertEqual(lower("whAT"), "what") + + +if __name__ == "__main__": + unittest.main() diff --git a/strings/manacher.py b/strings/manacher.py index 5476e06839b7..deda2ace37a2 100644 --- a/strings/manacher.py +++ b/strings/manacher.py @@ -1,107 +1,57 @@ -def palindromic_string(input_string: str) -> str: - """ - >>> palindromic_string('abbbaba') - 'abbba' - >>> palindromic_string('ababa') - 'ababa' - - Manacher’s algorithm which finds Longest palindromic Substring in linear time. - - 1. first this convert input_string("xyx") into new_string("x|y|x") where odd - positions are actual input characters. - 2. for each character in new_string it find corresponding length and store the - length and l,r to store previously calculated info.(please look the explanation - for details) - - 3. return corresponding output_string by removing all "|" - """ - max_length = 0 - - # if input_string is "aba" than new_input_string become "a|b|a" - new_input_string = "" - output_string = "" - - # append each character + "|" in new_string for range(0, length-1) - for i in input_string[: len(input_string) - 1]: - new_input_string += i + "|" - # append last character - new_input_string += input_string[-1] - - # we will store the starting and ending of previous furthest ending palindromic - # substring - l, r = 0, 0 - - # length[i] shows the length of palindromic substring with center i - length = [1 for i in range(len(new_input_string))] - - # for each character in new_string find corresponding palindromic string - for i in range(len(new_input_string)): - k = 1 if i > r else min(length[l + r - i] // 2, r - i + 1) - while ( - i - k >= 0 - and i + k < len(new_input_string) - and new_input_string[k + i] == new_input_string[i - k] - ): - k += 1 - - length[i] = 2 * k - 1 - - # does this string is ending after the previously explored end (that is r) ? - # if yes the update the new r to the last index of this - if i + k - 1 > r: - l = i - k + 1 # noqa: E741 - r = i + k - 1 - - # update max_length and start position - if max_length < length[i]: - max_length = length[i] - start = i - - # create that string - s = new_input_string[start - max_length // 2 : start + max_length // 2 + 1] - for i in s: - if i != "|": - output_string += i - - return output_string - - -if __name__ == "__main__": - import doctest - - doctest.testmod() - -""" -...a0...a1...a2.....a3......a4...a5...a6.... - -consider the string for which we are calculating the longest palindromic substring is -shown above where ... are some characters in between and right now we are calculating -the length of palindromic substring with center at a5 with following conditions : -i) we have stored the length of palindromic substring which has center at a3 (starts at - l ends at r) and it is the furthest ending till now, and it has ending after a6 -ii) a2 and a4 are equally distant from a3 so char(a2) == char(a4) -iii) a0 and a6 are equally distant from a3 so char(a0) == char(a6) -iv) a1 is corresponding equal character of a5 in palindrome with center a3 (remember - that in below derivation of a4==a6) - -now for a5 we will calculate the length of palindromic substring with center as a5 but -can we use previously calculated information in some way? -Yes, look the above string we know that a5 is inside the palindrome with center a3 and -previously we have have calculated that -a0==a2 (palindrome of center a1) -a2==a4 (palindrome of center a3) -a0==a6 (palindrome of center a3) -so a4==a6 - -so we can say that palindrome at center a5 is at least as long as palindrome at center -a1 but this only holds if a0 and a6 are inside the limits of palindrome centered at a3 -so finally .. - -len_of_palindrome__at(a5) = min(len_of_palindrome_at(a1), r-a5) -where a3 lies from l to r and we have to keep updating that - -and if the a5 lies outside of l,r boundary we calculate length of palindrome with -bruteforce and update l,r. - -it gives the linear time complexity just like z-function -""" +import unittest + + +def longest_palindromic_substring(string: str) -> str: + """ + Manacher’s algorithm which finds Longest Palindromic Substring. + Source: https://en.wikipedia.org/wiki/Longest_palindromic_substring + """ + if string == "": + return "" + + # create string with separators: "aba" -> "a|b|a" + new_string = "|".join(list(string)) + + left = right = 0 # start/end index of longest palindrome so far + # length[i] shows the length of palindromic substring with center i + length = [1] * len(new_string) + start = max_length = 0 + + # for each character in new_string find the corresponding max palindrome length + # and store the length and left, right boundary + for i, _ in enumerate(new_string): + k = 1 if i > right else min(length[left + right - i] // 2, right - i + 1) + while ( + i - k >= 0 + and i + k < len(new_string) + and new_string[k + i] == new_string[i - k] + ): + k += 1 + + length[i] = 2 * k - 1 + + # update the right and left index if string ends after the previously right + if i + k - 1 > right: + left = i - k + 1 # noqa: E741 + right = i + k - 1 + + if max_length < length[i]: + max_length = length[i] + start = i + + s = new_string[start - max_length // 2 : start + max_length // 2 + 1] + return "".join(s.split("|")) + + +class TestLongestPalindrome(unittest.TestCase): + def test_longest_palindromic_substring(self): + self.assertEqual(longest_palindromic_substring("abbbaba"), "abbba") + self.assertEqual(longest_palindromic_substring("ababa"), "ababa") + self.assertEqual(longest_palindromic_substring(""), "") + self.assertEqual(longest_palindromic_substring("a"), "a") + self.assertEqual(longest_palindromic_substring("aa"), "aa") + self.assertEqual(longest_palindromic_substring("abc"), "b") + + +if __name__ == "__main__": + unittest.main() diff --git a/strings/rabin_karp.py b/strings/rabin_karp.py index 81ca611a76b3..d866b1397277 100644 --- a/strings/rabin_karp.py +++ b/strings/rabin_karp.py @@ -4,7 +4,7 @@ modulus = 1000003 -def rabin_karp(pattern: str, text: str) -> bool: +def rabin_karp(pattern, text): """ The Rabin-Karp Algorithm for finding a pattern within a piece of text with complexity O(nm), most efficient when it is used with multiple patterns @@ -51,7 +51,7 @@ def rabin_karp(pattern: str, text: str) -> bool: return False -def test_rabin_karp() -> None: +def test_rabin_karp(): """ >>> test_rabin_karp() Success.