数组最小元素和题解 | 豆包MarsCode AI刷题

45 阅读2分钟

学习记录与心得:最小数组元素和问题解析

问题描述

小C希望构造一个包含n个元素的数组,且满足以下条件:

  • 数组中的所有元素两两不同。
  • 数组所有元素的最大公约数为 k。
  • 数组元素之和尽可能小。
  • 任务是输出该数组元素之和的最小值。

题意分析

本题的目标是构造一个满足特定条件的数组,并求出其元素和的最小值。具体要求如下:

  1. 数组包含 ( n ) 个元素,且所有元素两两不同
  2. 数组中所有元素的最大公约数(GCD)为 ( k )
  3. 数组元素的和尽可能小

通过本题可以学习如何结合数学和编程解决优化问题,理解最大公约数的性质,以及如何生成满足条件的最优解。


问题分析

条件分析

  1. 两两不同:意味着数组中的元素不能重复。
  2. 最大公约数为 ( k ):数组中所有元素的公共因子必须是 ( k ),因此数组中的每个元素必定是 ( k ) 的倍数。
  3. 和尽可能小:最小化数组和的关键是选择最小的 ( n ) 个 ( k ) 的倍数。

关键思路

根据条件分析得知,数组的所有元素必须是 ( k ) 的倍数,即:

ai=k×xi(i=1,2,,n)a_i = k \times x_i \quad (i = 1, 2, \dots, n)

其中xix_i 为整数。为了使数组的 GCD 为 ( k ),数组元素可以取: [ a1=k,  a2=2k,  a3=3k,  ,  an=nka_1 = k, \; a_2 = 2k, \; a_3 = 3k, \; \dots, \; a_n = nk ] 这样确保了数组中的每个元素是 ( k ) 的倍数,并且两两不同,同时 ( xix_i ) 连续的整数保证了 GCD 为 ( k )。

数学推导

数组元素为 (k,2k,,nkk, 2k, \dots, nk),其和为:

sum=k+2k+3k++nk=k×(1+2+3++n)\text{sum} = k + 2k + 3k + \dots + nk = k \times (1 + 2 + 3 + \dots + n)

其中 (1+2++n1 + 2 + \dots + n) 是前 ( n ) 个正整数的和,可以用公式计算: [ 1+2++n=n×(n+1)21 + 2 + \dots + n = \frac{n \times (n + 1)}{2} ] 因此,数组元素和的最小值为: [ sum=k×n×(n+1)2\text{sum} = k \times \frac{n \times (n + 1)}{2} ]


示例解析

示例 1

输入:( n = 3, k = 1 )
步骤

  • 数组元素为 ( 1, 2, 3 )(即 ( 1k, 2k, 3k ))。
  • 元素和为 ( 1 + 2 + 3 = 6 )。

输出:6


示例 2

输入:( n = 2, k = 2 )
步骤

  • 数组元素为 ( 2, 4 )(即 ( 1k, 2k ))。
  • 元素和为 ( 2 + 4 = 6 )。

输出:6


示例 3

输入:( n = 4, k = 3 )
步骤

  • 数组元素为 ( 3, 6, 9, 12 )(即 ( 1k, 2k, 3k, 4k ))。
  • 元素和为 ( 3 + 6 + 9 + 12 = 30 )。

输出:30


图解

通过图表更清晰地了解问题:

( n )( k )数组元素元素和
31( [1, 2, 3] )6
22( [2, 4] )6
43( [3, 6, 9, 12] )30

代码详解

以下是解决问题的完整代码:

def solution(n: int, k: int) -> int:
    # 初始化一个列表来存储 `k` 的倍数
    multiples = []
    
    # 从 `k` 开始,生成 `n` 个不同的 `k` 的倍数
    current = k
    while len(multiples) < n:
        # 如果当前数不在列表中,添加到列表
        if current not in multiples:
            multiples.append(current)
        # 增加 `k`,继续生成下一个倍数
        current += k
    
    # 计算这些倍数的和
    result = sum(multiples)
    
    return result

if __name__ == '__main__':
    # 测试用例
    print(solution(n=3, k=1) == 6)  # 输出 True
    print(solution(n=2, k=2) == 6)  # 输出 True
    print(solution(n=4, k=3) == 30) # 输出 True

代码解释

  1. 初始化列表:创建一个空列表 multiples 来存储数组元素。
  2. 生成倍数:从k开始,依次生成 (k,2k,3k,k, 2k, 3k, \dots ),直到找到n个不同的倍数。
  3. 计算和:通过 sum(multiples) 求出所有元素的和。

时间复杂度

  • 生成 ( n ) 个倍数需要线性时间 ( O(n)O(n) )。
  • 求和操作为 (O(n) O(n) )。 因此,总时间复杂度为 (O(n)O(n))。

学习心得

  1. 数学在算法中的重要性: 本题的关键在于理解数学公式与问题条件的关联。例如,通过等差数列公式计算元素和,大幅简化了问题的计算复杂度。相比逐项累加,这种方法更加高效且清晰。
  2. 最大公约数的性质: 在构造数组时,数组元素必须是k的倍数,且选择最小的n个倍数可以确保数组的最大公约数为k。这一逻辑清晰地体现了最大公约数的应用。 3.问题的分步解决思路 复杂问题的解决需要逐步分解。本题通过“元素构造”和“求和”两个步骤完成,体现了算法设计的条理性。
  3. 数学优化:利用等差数列公式快速求解数组和,避免了逐项累加的低效计算。
  4. 代码设计:分步骤生成倍数、避免重复计算,是提升代码效率的关键。
  5. 泛化能力:这种倍数生成的方法可以推广到其他需要构造满足条件数组的场景。