Skip to content

Commit f467350

Browse files
committed
feat: add algorithm 95 to find the longest amicable chain
1 parent ab3769c commit f467350

File tree

1 file changed

+34
-24
lines changed

1 file changed

+34
-24
lines changed

project_euler/problem_095/sol1.py

Lines changed: 34 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,31 +11,43 @@
1111
chain.
1212
"""
1313

14-
15-
def sum_of_proper_divisors(n):
16-
"""Calculate the sum of proper divisors of n."""
17-
if n < 2:
14+
def sum_of_proper_divisors(number: int) -> int:
15+
"""Calculate the sum of proper divisors of the given number.
16+
17+
>>> sum_of_proper_divisors(6)
18+
6
19+
>>> sum_of_proper_divisors(28)
20+
28
21+
>>> sum_of_proper_divisors(12)
22+
16
23+
>>> sum_of_proper_divisors(1)
24+
0
25+
"""
26+
if number < 2:
1827
return 0 # Proper divisors of 0 and 1 are none.
19-
total = 1 # Start with 1, since it is a proper divisor of any n > 1
20-
sqrt_n = int(n**0.5) # Calculate the integer square root of n.
28+
total = 1 # Start with 1, since it is a proper divisor of any number > 1
29+
sqrt_n = int(number**0.5) # Calculate the integer square root of number.
2130

22-
# Loop through possible divisors from 2 to the square root of n
31+
# Loop through possible divisors from 2 to the square root of number
2332
for i in range(2, sqrt_n + 1):
24-
if n % i == 0: # Check if i is a divisor of n
33+
if number % i == 0: # Check if i is a divisor of number
2534
total += i # Add the divisor
26-
if i != n // i: # Avoid adding the square root twice
27-
total += n // i # Add the corresponding divisor (n/i)
35+
if i != number // i: # Avoid adding the square root twice
36+
total += number // i # Add the corresponding divisor (number/i)
2837

2938
return total
3039

40+
def find_longest_amicable_chain(limit: int) -> int:
41+
"""Find the smallest member of the longest amicable chain under a given limit.
3142
32-
def find_longest_amicable_chain(limit):
33-
"""Find the smallest member of the longest amicable chain under a given limit."""
43+
>>> find_longest_amicable_chain(10**3)
44+
624
45+
>>> find_longest_amicable_chain(10**6)
46+
14316
47+
"""
3448
sum_divisors = {} # Dictionary to store the sum of proper divisors for each number
3549
for i in range(1, limit + 1):
36-
sum_divisors[i] = sum_of_proper_divisors(
37-
i
38-
) # Calculate and store sum of proper divisors
50+
sum_divisors[i] = sum_of_proper_divisors(i) # Calculate and store sum of proper divisors
3951

4052
longest_chain = [] # To store the longest amicable chain found
4153
seen = {} # Dictionary to track numbers already processed
@@ -50,9 +62,7 @@ def find_longest_amicable_chain(limit):
5062
while current <= limit and current not in chain:
5163
chain.append(current) # Add the current number to the chain
5264
seen[current] = True # Mark this number as seen
53-
current = sum_divisors.get(
54-
current, 0
55-
) # Move to the next number in the chain
65+
current = sum_divisors.get(current, 0) # Move to the next number in the chain
5666

5767
# Check if we form a cycle and validate the chain
5868
if current in chain and current != start:
@@ -63,16 +73,16 @@ def find_longest_amicable_chain(limit):
6373
if len(chain) > len(longest_chain):
6474
longest_chain = chain # Update longest chain if this one is longer
6575

66-
return (
67-
min(longest_chain) if longest_chain else None
68-
) # Return the smallest member of the longest chain
76+
return min(longest_chain) if longest_chain else None # Return the smallest member of the longest chain
6977

78+
def solution() -> int:
79+
"""Return the smallest member of the longest amicable chain under one million.
7080
71-
def solution():
72-
"""Return the smallest member of the longest amicable chain under one million."""
81+
>>> solution()
82+
14316
83+
"""
7384
return find_longest_amicable_chain(10**6)
7485

75-
7686
if __name__ == "__main__":
7787
smallest_member = solution() # Call the solution function
7888
print(smallest_member) # Output the smallest member of the longest amicable chain

0 commit comments

Comments
 (0)