问题描述
小C最近发现了一种称为“Firm”的数组。如果一个数组的最大公约数大于 1,则称该数组为“Firm”数组。给定一个长度为 N 的数组 A,你可以在每次操作中将任何一个元素增加或减少 1。
现在,你需要确定将数组 A 转换为“Firm”数组所需的最少操作次数。
解题思路
我们需要将一个数组 A 转换为“Firm”数组,即数组的最大公约数(GCD)大于 1。为了实现这一点,我们可以在每次操作中将数组中的任何一个元素增加或减少 1。目标是找到将数组 A 转换为“Firm”数组所需的最少操作次数。
数据结构与算法步骤
-
生成质数:首先,我们生成小于
n的所质数。算法原理:使用埃拉托斯特尼筛法。
- 首先创建布尔列表
is_prime,初始设定除 0 和 1 外所有数为质数(is_prime[0] = is_prime[1] = False,其余为True)。 - 从 2 开始到
sqrt(n),对于每个质数i,将其倍数j(从i * i开始,步长为i)标记为非质数(is_prime[j] = False)。 - 最后遍历
is_prime列表,将值为True的索引i(即质数)添加到primes列表并返回。
- 首先创建布尔列表
solution函数
- 计算操作次数:计算将数组
A转换为 “Firm” 数组所需的最少操作次数。
-
实现步骤:
-
首先,初始化
ret为正无穷大,用于存储最终最少操作次数。 -
调用
generate_primes函数生成小于 1000 的质数列表primes。 -
遍历质数列表
primes中的每个质数p:-
初始化
cur为 0,用于记录当前质数p下的操作次数。 -
对于数组
A中的每个元素element:- 计算
element除以p的余数remainder。 cur增加min(remainder, p - remainder),即把元素调整为能被p整除的最少操作次数(通过增加余数或减少到p - remainder)。
- 计算
-
更新
ret为cur和ret中的较小值,确保ret始终存储当前找到的最少操作次数。
-
-
最后返回
ret,即为将数组A转换为 “Firm” 数组所需的最少操作次数。
-
代码展示
import math
def generate_primes(n):
primes = []
if n <= 1:
return primes
is_prime = [True] * n
is_prime[0] = is_prime[1] = False
for i in range(2, int(math.sqrt(n)) + 1):
if is_prime[i]:
for j in range(i * i, n, i):
is_prime[j] = False
for i in range(2, n):
if is_prime[i]:
primes.append(i)
return primes
def solution(N: int, A: list) -> int:
ret = float('inf')
primes = generate_primes(1000)
for p in primes:
cur = 0
for element in A:
remainder = element % p
cur += min(remainder, p - remainder)
ret = min(ret, cur)
return ret
if __name__ == '__main__':
print(solution(N = 4, A = [3, 16, 8, 9]) == 2)
print(solution(N = 3, A = [5, 10, 15]) == 0)
print(solution(N = 5, A = [1, 2, 3, 4, 5]) == 3)
测试样例
样例1:
输入:
N = 4, A = [3, 16, 8, 9]
输出:2
样例2:
输入:
N = 3, A = [5, 10, 15]
输出:0
样例3:
输入:
N = 5, A = [1, 2, 3, 4, 5]
输出:3
埃拉托斯特尼筛法
-
定义
- 埃拉托斯特尼筛法(Sieve of Eratosthenes)是一种古老而高效的算法,用于找出给定范围内的所有质数。它的基本思想是通过筛选的方式,逐步排除合数,剩下的就是质数。
-
算法步骤
-
假设要找出小于或等于的所有质数。
-
首先,创建一个布尔型数组(或列表),长度为,并初始化为(假设所有数都是质数)。然后将和设为,因为 0 和 1 不是质数。
-
从开始,因为是最小的质数。对于每个数(从到):
- 如果为,则是质数。然后将的倍数(从开始,因为小于的的倍数已经在前面的迭代中被标记过了,例如在处理的时候已经考虑过了,所以从开始就可以。步长为)对应的设为,这些数就是合数。
-
最后,遍历数组,所有值为的索引对应的数就是质数。
-
-
时间复杂度
- 埃拉托斯特尼筛法的时间复杂度为。这比简单地检查每个数是否为质数(例如,对于每个数,检查从到是否能整除,时间复杂度为)要高效得多。
-
示例代码
def generate_primes(n):
primes = []
if n <= 1:
return primes
is_prime = [True] * n
is_prime[0] = is_prime[1] = False
for i in range(2, int(math.sqrt(n)) + 1):
if is_prime[i]:
for j in range(i * i, n, i):
is_prime[j] = False
for i in range(2, n):
if is_prime[i]:
primes.append(i)
return primes
在这个示例中,函数generate_primes实现了埃拉托斯特尼筛法来找出小于的所有质数。首先初始化了is_prime列表,然后按照筛法的步骤标记合数,最后将质数添加到primes列表并返回。