今天给大家分享一下每日刷题的题目解析和经验分享,本系列预计会推出五期,今天给大家带来的是第一期的分享。
第一题——数组元素之和最小化
问题描述
小C希望构造一个包含n个元素的数组,且满足以下条件:
- 数组中的所有元素两两不同。
- 数组所有元素的最大公约数为
k。 - 数组元素之和尽可能小。
任务是输出该数组元素之和的最小值。
测试样例
样例1:
输入:
n = 3 ,k = 1
输出:6
样例2:
输入:
n = 2 ,k = 2
输出:6
样例3:
输入:
n = 4 ,k = 3
输出:30
解决方案
-
理解最大公约数(GCD) :
- 数组中的所有元素的最大公约数为
k,意味着每个元素都可以表示为k的倍数。 - 因此,数组中的每个元素可以表示为
k * i,其中i是一个正整数。
- 数组中的所有元素的最大公约数为
-
构造数组:
- 为了满足数组元素两两不同且和最小,我们可以从
k开始,依次选择k, 2k, 3k, ..., nk作为数组的元素。 - 这样构造的数组满足所有元素两两不同,且最大公约数为
k。
- 为了满足数组元素两两不同且和最小,我们可以从
-
计算数组元素之和:
- 数组元素之和为
k + 2k + 3k + ... + nk。 - 这个和可以表示为
k * (1 + 2 + 3 + ... + n)。 - 根据等差数列求和公式,
1 + 2 + 3 + ... + n = n * (n + 1) / 2。 - 因此,数组元素之和为
k * n * (n + 1) / 2。
- 数组元素之和为
总结
我们可以构造出一个满足条件的数组,并且计算出数组元素之和的最小值。这个最小值可以通过公式 k * n * (n + 1) / 2 直接计算得出。
public class Main {
public static int solution(int n, int k) {
// 代码实现如下:
int result = 0;
for (int i = 1; i <= n; i++) {
result += i*k;
}
return result;
}
// 测试用例如下:
public static void main(String[] args) {
System.out.println(solution(3, 1) == 6);
System.out.println(solution(2, 2) == 6);
System.out.println(solution(4, 3) == 30);
}
}
复杂度分析
时间复杂度
-
时间复杂度:
O(n)- 代码中包含一个
for循环,循环次数为n,因此时间复杂度为O(n)。
- 代码中包含一个
空间复杂度
-
空间复杂度:
O(1)- 代码中只使用了常数个额外变量(
result和i),没有使用额外的数据结构,因此空间复杂度为O(1)。
- 代码中只使用了常数个额外变量(
第二题——找单独的数
问题描述
在一个班级中,每位同学都拿到了一张卡片,上面有一个整数。有趣的是,除了一个数字之外,所有的数字都恰好出现了两次。现在需要你帮助班长小C快速找到那个拿了独特数字卡片的同学手上的数字是什么。
要求:
- 设计一个算法,使其时间复杂度为 O(n),其中 n 是班级的人数。
- 尽量减少额外空间的使用,以体现你的算法优化能力。
测试样例
样例1:
输入:
cards = [1, 1, 2, 2, 3, 3, 4, 5, 5]
输出:4
解释:拿到数字 4 的同学是唯一一个没有配对的。
样例2:
输入:
cards = [0, 1, 0, 1, 2]
输出:2
解释:数字 2 只出现一次,是独特的卡片。
样例3:
输入:
cards = [7, 3, 3, 7, 10]
输出:10
解释:10 是班级中唯一一个不重复的数字卡片。
约束条件:
- 1 ≤ cards.length ≤ 1001
- 0 ≤ cards[i] ≤ 1000
- 班级人数为奇数
- 除了一个数字卡片只出现一次外,其余每个数字卡片都恰好出现两次
解决方案
我们需要在一个整数数组中找到那个只出现一次的数字。数组中的其他数字都恰好出现两次。
数据结构的选择
由于题目要求时间复杂度为 O(n),并且尽量减少额外空间的使用,我们可以利用异或(XOR)操作的特性来解决这个问题。
异或操作的特性
- 相同数字的异或:对于任何整数
x,x ^ x = 0。这意味着如果一个数字出现两次,它们异或的结果将是 0。 - 与 0 的异或:对于任何整数
x,x ^ 0 = x。这意味着如果一个数字只出现一次,它与 0 异或的结果将是它本身。
算法步骤
- 初始化结果变量:我们初始化一个变量
result为 0,用于存储异或操作的结果。 - 遍历数组:我们遍历数组中的每一个数字。
- 异或操作:对每一个数字进行异或操作,并将结果存储在
result中。 - 返回结果:最终,
result中存储的就是那个单独的数字。
总结
通过利用异或操作的特性,我们可以在 O(n) 的时间复杂度内找到那个只出现一次的数字,并且不需要额外的空间。
public class Main {
public static int solution(int[] cards) {
// 代码实现如下:
int result = 0;
for (int card : cards) {
result ^=card;
}
return result;
}
// 测试用例如下:
public static void main(String[] args) {
System.out.println(solution(new int[]{1, 1, 2, 2, 3, 3, 4, 5, 5}) == 4);
System.out.println(solution(new int[]{0, 1, 0, 1, 2}) == 2);
System.out.println(solution(new int[]{7, 3, 3, 7, 10}) == 10);
}
}