在算法学习中,如何根据特定规则构造一个数组并优化其某一属性(如最小化元素和)是一个经典问题。这篇博客将带你逐步分析一道相关题目,帮助你理解问题背后的数学规律与算法实现。
题目描述
小C需要构造一个包含 ( n ) 个元素的数组,且满足以下条件:
- 数组中的所有元素两两不同。
- 数组所有元素的最大公约数为 ( k )。
- 数组元素之和尽可能小。
任务:输出该数组元素之和的最小值。
示例
输入:
- ( 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] |
解题思路
分析题目条件后,我们可以逐步推导构造数组的规则:
- 两两不同:数组中的元素需要互不相同。
- 选择数组元素时,可以从一个等差数列中取值。
- 最大公约数为 ( k ):
- 数组中所有数必须是 ( k ) 的倍数。
- 最小的数可以是 ( k ),随后依次为 ( 2k, 3k, \ldots )。
- 元素之和最小:
- 按照上述规则,从小到大依次选取 ( 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
}
}
代码详解
- 循环构造数组:
- 使用变量
flag从最小的倍数 ( k ) 开始,每次增加 ( k )。
- 使用变量
- 累加结果:
- 将当前的
flag累加到结果res中。
- 将当前的
- 返回结果:
- 最终的和即为所求最小值。
举例
以 ( n = 4, k = 3 ) 为例,构造数组的步骤如下:
- 从 ( 3 ) 开始,依次取 ( 6, 9, 12 ):
- 数组为 [3, 6, 9, 12]。
- 计算和:
- ( 3+6+9+12 = 30 )。
时间复杂度分析
算法效率
- 循环:
- 代码中存在一个长度为 ( n ) 的循环,时间复杂度为 ( O(n) )。
- 常数时间操作:
- 每次迭代的计算(累加)为常数时间操作 ( O(1) )。
总体复杂度
[ O(n) ]
总结
这道题的核心在于:
- 理解最大公约数的条件限制。
- 运用等差数列的性质,简化计算。
通过以上方法,我们不仅可以快速得出结果,还能利用数学规律优化代码。