刷题451. 最小操作数使数组变为 Firm 数组| 豆包MarsCode AI 刷题

33 阅读4分钟

问题描述

小C最近发现了一种称为“Firm”的数组。如果一个数组的最大公约数大于 1,则称该数组为“Firm”数组。给定一个长度为 N 的数组 A,你可以在每次操作中将任何一个元素增加或减少 1

现在,你需要确定将数组 A 转换为“Firm”数组所需的最少操作次数。

解题思路

我们需要将一个数组 A 转换为“Firm”数组,即数组的最大公约数(GCD)大于 1。为了实现这一点,我们可以在每次操作中将数组中的任何一个元素增加或减少 1。目标是找到将数组 A 转换为“Firm”数组所需的最少操作次数。

数据结构与算法步骤

  1. 生成质数:首先,我们生成小于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函数

  1. 计算操作次数:计算将数组A转换为 “Firm” 数组所需的最少操作次数。
  • 实现步骤

    1. 首先,初始化ret为正无穷大,用于存储最终最少操作次数。

    2. 调用generate_primes函数生成小于 1000 的质数列表primes

    3. 遍历质数列表primes中的每个质数p

      • 初始化cur为 0,用于记录当前质数p下的操作次数。

      • 对于数组A中的每个元素element

        • 计算element除以p的余数remainder
        • cur增加min(remainder, p - remainder),即把元素调整为能被p整除的最少操作次数(通过增加余数或减少到p - remainder)。
      • 更新retcurret中的较小值,确保ret始终存储当前找到的最少操作次数。

    4. 最后返回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

埃拉托斯特尼筛法

  1. 定义

    • 埃拉托斯特尼筛法(Sieve of Eratosthenes)是一种古老而高效的算法,用于找出给定范围内的所有质数。它的基本思想是通过筛选的方式,逐步排除合数,剩下的就是质数。
  2. 算法步骤

    • 假设要找出小于或等于的所有质数。

    • 首先,创建一个布尔型数组(或列表),长度为,并初始化为(假设所有数都是质数)。然后将和设为,因为 0 和 1 不是质数。

    • 从开始,因为是最小的质数。对于每个数(从到):

      • 如果为,则是质数。然后将的倍数(从开始,因为小于的的倍数已经在前面的迭代中被标记过了,例如在处理的时候已经考虑过了,所以从开始就可以。步长为)对应的设为,这些数就是合数。
    • 最后,遍历数组,所有值为的索引对应的数就是质数。

  3. 时间复杂度

    • 埃拉托斯特尼筛法的时间复杂度为。这比简单地检查每个数是否为质数(例如,对于每个数,检查从到是否能整除,时间复杂度为)要高效得多。
  4. 示例代码

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列表并返回。