构造数组问题:最小化元素和的思路与实现 | 豆包MarsCode AI刷题

72 阅读3分钟

在算法学习中,如何根据特定规则构造一个数组并优化其某一属性(如最小化元素和)是一个经典问题。这篇博客将带你逐步分析一道相关题目,帮助你理解问题背后的数学规律与算法实现。


题目描述

小C需要构造一个包含 ( n ) 个元素的数组,且满足以下条件:

  1. 数组中的所有元素两两不同。
  2. 数组所有元素的最大公约数为 ( k )。
  3. 数组元素之和尽可能小。

任务:输出该数组元素之和的最小值。


示例

输入

  • ( n = 3 ),( k = 1 )

输出

  • 最小元素和为 ( 6 )。

解释: 当 ( k = 1 ) 时,最小和的数组是 [1, 2, 3],元素和为 ( 1+2+3=6 )。


其他测试样例

输入输出数组
( n = 3, k = 1 )( 6 )[1, 2, 3]
( n = 2, k = 2 )( 6 )[2, 4]
( n = 4, k = 3 )( 30 )[3, 6, 9, 12]

解题思路

分析题目条件后,我们可以逐步推导构造数组的规则:

  1. 两两不同:数组中的元素需要互不相同。
    • 选择数组元素时,可以从一个等差数列中取值。
  2. 最大公约数为 ( k )
    • 数组中所有数必须是 ( k ) 的倍数。
    • 最小的数可以是 ( k ),随后依次为 ( 2k, 3k, \ldots )。
  3. 元素之和最小
    • 按照上述规则,从小到大依次选取 ( n ) 个数。

因此,最优的数组构造方式是: [ [k, 2k, 3k, \ldots, nk] ]

数学推导

该数组的和为: [ S = k \cdot (1 + 2 + 3 + \cdots + n) ] 其中 ( 1+2+\cdots+n ) 是前 ( n ) 个正整数的和,公式为: [ \text{Sum} = \frac{n \cdot (n + 1)}{2} ] 所以,总和可以表示为: [ S = k \cdot \frac{n \cdot (n + 1)}{2} ]

这一公式可以帮助我们直接计算结果,而无需真正构造数组。


代码实现

下面的代码实现了这一逻辑:

public class Main {
    public static int solution(int n, int k) {
        // 初始化结果
        int res = 0;
        // flag 记录当前元素值,初始为 k
        int flag = k;
        // 构造数组并累加和
        for (int i = 0; i < n; ++i) {
            res += flag;
            flag += k; // 下一个元素
        }
        return res;
    }

    public static void main(String[] args) {
        // 测试样例
        System.out.println(solution(3, 1) == 6); // 输出 true
        System.out.println(solution(2, 2) == 6); // 输出 true
        System.out.println(solution(4, 3) == 30); // 输出 true
    }
}

代码详解

  1. 循环构造数组
    • 使用变量 flag 从最小的倍数 ( k ) 开始,每次增加 ( k )。
  2. 累加结果
    • 将当前的 flag 累加到结果 res 中。
  3. 返回结果
    • 最终的和即为所求最小值。

举例

以 ( n = 4, k = 3 ) 为例,构造数组的步骤如下:

  1. 从 ( 3 ) 开始,依次取 ( 6, 9, 12 ):
    • 数组为 [3, 6, 9, 12]。
  2. 计算和:
    • ( 3+6+9+12 = 30 )。

时间复杂度分析

算法效率

  1. 循环
    • 代码中存在一个长度为 ( n ) 的循环,时间复杂度为 ( O(n) )。
  2. 常数时间操作
    • 每次迭代的计算(累加)为常数时间操作 ( O(1) )。

总体复杂度

[ O(n) ]


总结

这道题的核心在于:

  1. 理解最大公约数的条件限制。
  2. 运用等差数列的性质,简化计算。

通过以上方法,我们不仅可以快速得出结果,还能利用数学规律优化代码。