📅  最后修改于: 2023-12-03 15:41:37.819000             🧑  作者: Mango
在数学中,GCD(最大公约数)是两个或多个整数的最大公因数。本题要求我们计算具有GCD且N等于数字本身的数字。
我们可以从最简单的做法开始,逐步优化。首先,我们可以枚举所有的数字 $N$,然后对每个数字 $N$ 以及 $[1, N-1]$ 中的数字进行 GCD 计算,如果与 $N$ 的 GCD 为 $1$,那么这个数字就符合条件。
def is_gcd_n(x: int) -> bool:
for i in range(1, x):
if math.gcd(i, x) == 1:
return False
return True
def find_gcd_n_list(n: int) -> List[int]:
res = []
for i in range(2, n+1):
if is_gcd_n(i):
res.append(i)
return res
这个做法的时间复杂度为 $O(N^2 \log N)$,对于较大的 $N$,可能会超时。接下来,我们可以优化一下枚举的范围,由于 $N$ 除了 $1$ 以外没有其他的因数,那么符合条件的数字一定是因数不超过 $\sqrt{N}$ 的数字,所以我们可以只枚举到 $\sqrt{N}$,这样的时间复杂度为 $O(N \sqrt{N} \log N)$。
def find_gcd_n_list(n: int) -> List[int]:
res = []
for i in range(2, n+1):
bound = int(math.sqrt(i))+1
flag = True
for j in range(2, bound):
if i % j == 0 and math.gcd(j, i) == 1:
flag = False
break
if flag:
res.append(i)
return res
我们还可以再次优化,注意到一个数与一个质数的 GCD 要么是 $1$ 要么是该质数,因此我们只需要枚举质数,然后计算其幂次,再将不超过 $N$ 的数字加入结果集中即可。这样的时间复杂度为 $O(\sqrt{N} \log N)$。
def find_gcd_n_list(n: int) -> List[int]:
res = []
bound = int(math.sqrt(n))+1
for i in range(2, bound):
if is_prime(i):
j = i
while j <= n:
res.append(j)
j *= i
return res
def is_prime(x: int) -> bool:
if x < 2:
return False
for i in range(2, int(x ** 0.5) + 1):
if x % i == 0:
return False
return True
本题我们一开始从暴力开始,逐步优化算法,开发者们一定要注意这种自底向上的思路。同时,优化算法不仅要注重时间复杂度,还要注重空间复杂度,开发者们应该对常用的算法和数据结构有一定掌握,这样才能设计出时间和空间都优秀的算法。