Skip to content

Commit bbdaeb1

Browse files
committed
Add solution for Project Euler 70, Fixes: TheAlgorithms#2695
1 parent 6541236 commit bbdaeb1

File tree

3 files changed

+93
-0
lines changed

3 files changed

+93
-0
lines changed

Diff for: DIRECTORY.md

+2
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,8 @@
654654
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_63/sol1.py)
655655
* Problem 67
656656
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_67/sol1.py)
657+
* Problem 70
658+
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_70/sol1.py)
657659
* Problem 76
658660
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_76/sol1.py)
659661
* Problem 97

Diff for: project_euler/problem_70/__init__.py

Whitespace-only changes.

Diff for: project_euler/problem_70/sol1.py

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
"""
2+
Project Euler 70
3+
https://projecteuler.net/problem=70
4+
5+
Euler's Totient function, φ(n) [sometimes called the phi function], is used to
6+
determine the number of positive numbers less than or equal to n which are
7+
relatively prime to n. For example, as 1, 2, 4, 5, 7, and 8, are all less than
8+
nine and relatively prime to nine, φ(9)=6.
9+
10+
The number 1 is considered to be relatively prime to every positive number, so
11+
φ(1)=1.
12+
13+
Interestingly, φ(87109)=79180, and it can be seen that 87109 is a permutation
14+
of 79180.
15+
16+
Find the value of n, 1 < n < 10^7, for which φ(n) is a permutation of n and
17+
the ratio n/φ(n) produces a minimum.
18+
"""
19+
20+
21+
def solution(max: int) -> int:
22+
"""
23+
This is essentially brute force. Calculate all totients up to 10^7 and
24+
find the minimum ratio of n/φ(n) that way. To minimize the ratio, we want
25+
to minimize n and maximize φ(n) as much as possible, so we can store the
26+
minimum fraction's numerator and denominator and calculate new fractions
27+
with each totient to compare against. To avoid dividing by zero, I opt to
28+
use cross multiplication.
29+
"""
30+
31+
min_num = 1 # i
32+
min_den = 0 # φ(i)
33+
totients = get_totients(max + 1)
34+
35+
for i in range(2, max + 1):
36+
t = totients[i]
37+
38+
if i * min_den < min_num * t and has_same_digits(i, t):
39+
min_num = i
40+
min_den = t
41+
42+
return min_num
43+
44+
45+
def get_totients(max_one: int) -> list:
46+
"""
47+
Calculates a list of totients from 0 to max_one exclusive, using the
48+
definition of Euler's product formula:
49+
https://en.wikipedia.org/wiki/Euler's_totient_function#Euler's_product_formula
50+
"""
51+
totients = [0] * max_one
52+
53+
for i in range(0, max_one):
54+
totients[i] = i
55+
56+
for i in range(2, max_one):
57+
if totients[i] == i:
58+
for j in range(i, max_one, i):
59+
totients[j] -= totients[j] // i
60+
61+
return totients
62+
63+
64+
def has_same_digits(num1: int, num2: int) -> bool:
65+
"""
66+
Return True if num1 and num2 have the same frequency of every digit, False
67+
otherwise.
68+
69+
digits[] is a frequency table where the index represents the digit from
70+
0-9, and the element stores the number of appearances. Increment the
71+
respective index every time you see the digit in num1, and decrement if in
72+
num2. At the end, if the numbers have the same digits, every index must
73+
contain 0.
74+
"""
75+
digits = [0] * 10
76+
77+
while num1 > 0 and num2 > 0:
78+
digits[num1 % 10] += 1
79+
digits[num2 % 10] -= 1
80+
num1 //= 10
81+
num2 //= 10
82+
83+
for digit in digits:
84+
if digit != 0:
85+
return False
86+
87+
return True
88+
89+
90+
if __name__ == "__main__":
91+
print(solution(10000000))

0 commit comments

Comments
 (0)