Merge branch 'TheAlgorithms:master' into fix-mypy-errs-5

This commit is contained in:
Tianyi Zheng 2023-01-12 10:24:06 -05:00 committed by GitHub
commit 4823467ab6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 146 additions and 2 deletions

View File

@ -16,6 +16,7 @@ fib_memoization runtime: 0.0107 ms
fib_binet runtime: 0.0174 ms fib_binet runtime: 0.0174 ms
""" """
from functools import lru_cache
from math import sqrt from math import sqrt
from time import time from time import time
@ -92,6 +93,39 @@ def fib_recursive(n: int) -> list[int]:
return [fib_recursive_term(i) for i in range(n + 1)] return [fib_recursive_term(i) for i in range(n + 1)]
def fib_recursive_cached(n: int) -> list[int]:
"""
Calculates the first n (0-indexed) Fibonacci numbers using recursion
>>> fib_iterative(0)
[0]
>>> fib_iterative(1)
[0, 1]
>>> fib_iterative(5)
[0, 1, 1, 2, 3, 5]
>>> fib_iterative(10)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
>>> fib_iterative(-1)
Traceback (most recent call last):
...
Exception: n is negative
"""
@lru_cache(maxsize=None)
def fib_recursive_term(i: int) -> int:
"""
Calculates the i-th (0-indexed) Fibonacci number using recursion
"""
if i < 0:
raise Exception("n is negative")
if i < 2:
return i
return fib_recursive_term(i - 1) + fib_recursive_term(i - 2)
if n < 0:
raise Exception("n is negative")
return [fib_recursive_term(i) for i in range(n + 1)]
def fib_memoization(n: int) -> list[int]: def fib_memoization(n: int) -> list[int]:
""" """
Calculates the first n (0-indexed) Fibonacci numbers using memoization Calculates the first n (0-indexed) Fibonacci numbers using memoization
@ -163,8 +197,9 @@ def fib_binet(n: int) -> list[int]:
if __name__ == "__main__": if __name__ == "__main__":
num = 20 num = 30
time_func(fib_iterative, num) time_func(fib_iterative, num)
time_func(fib_recursive, num) time_func(fib_recursive, num) # Around 3s runtime
time_func(fib_recursive_cached, num) # Around 0ms runtime
time_func(fib_memoization, num) time_func(fib_memoization, num)
time_func(fib_binet, num) time_func(fib_binet, num)

109
maths/gcd_of_n_numbers.py Normal file
View File

@ -0,0 +1,109 @@
"""
Gcd of N Numbers
Reference: https://en.wikipedia.org/wiki/Greatest_common_divisor
"""
from collections import Counter
def get_factors(
number: int, factors: Counter | None = None, factor: int = 2
) -> Counter:
"""
this is a recursive function for get all factors of number
>>> get_factors(45)
Counter({3: 2, 5: 1})
>>> get_factors(2520)
Counter({2: 3, 3: 2, 5: 1, 7: 1})
>>> get_factors(23)
Counter({23: 1})
>>> get_factors(0)
Traceback (most recent call last):
...
TypeError: number must be integer and greater than zero
>>> get_factors(-1)
Traceback (most recent call last):
...
TypeError: number must be integer and greater than zero
>>> get_factors(1.5)
Traceback (most recent call last):
...
TypeError: number must be integer and greater than zero
factor can be all numbers from 2 to number that we check if number % factor == 0
if it is equal to zero, we check again with number // factor
else we increase factor by one
"""
match number:
case int(number) if number == 1:
return Counter({1: 1})
case int(num) if number > 0:
number = num
case _:
raise TypeError("number must be integer and greater than zero")
factors = factors or Counter()
if number == factor: # break condition
# all numbers are factors of itself
factors[factor] += 1
return factors
if number % factor > 0:
# if it is greater than zero
# so it is not a factor of number and we check next number
return get_factors(number, factors, factor + 1)
factors[factor] += 1
# else we update factors (that is Counter(dict-like) type) and check again
return get_factors(number // factor, factors, factor)
def get_greatest_common_divisor(*numbers: int) -> int:
"""
get gcd of n numbers:
>>> get_greatest_common_divisor(18, 45)
9
>>> get_greatest_common_divisor(23, 37)
1
>>> get_greatest_common_divisor(2520, 8350)
10
>>> get_greatest_common_divisor(-10, 20)
Traceback (most recent call last):
...
Exception: numbers must be integer and greater than zero
>>> get_greatest_common_divisor(1.5, 2)
Traceback (most recent call last):
...
Exception: numbers must be integer and greater than zero
>>> get_greatest_common_divisor(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
1
>>> get_greatest_common_divisor("1", 2, 3, 4, 5, 6, 7, 8, 9, 10)
Traceback (most recent call last):
...
Exception: numbers must be integer and greater than zero
"""
# we just need factors, not numbers itself
try:
same_factors, *factors = map(get_factors, numbers)
except TypeError as e:
raise Exception("numbers must be integer and greater than zero") from e
for factor in factors:
same_factors &= factor
# get common factor between all
# `&` return common elements with smaller value (for Counter type)
# now, same_factors is something like {2: 2, 3: 4} that means 2 * 2 * 3 * 3 * 3 * 3
mult = 1
# power each factor and multiply
# for {2: 2, 3: 4}, it is [4, 81] and then 324
for m in [factor**power for factor, power in same_factors.items()]:
mult *= m
return mult
if __name__ == "__main__":
print(get_greatest_common_divisor(18, 45)) # 9