今天为大家详细讲一道基础的算法题,本文主要是介绍解题的一种具体思路,帮助大家学会怎么高效的刷题。
问题描述
在一个班级中,每位同学都拿到了一张卡片,上面有一个整数。有趣的是,除了一个数字之外,所有的数字都恰好出现了两次。现在需要你帮助班长小C快速找到那个拿了独特数字卡片的同学手上的数字是什么。要求算法的时间复杂度为 O(n)O(n),其中 nn 是班级的人数,并且尽量减少额外空间的使用,以体现你的算法优化能力。
做题思路
1. 问题分析
在这个问题中,我们需要在一个数组中找到唯一一个出现一次的数字,而其他数字都恰好出现两次。直接遍历数组并统计每个数字的出现次数会增加时间和空间复杂度,不符合题目要求。因此,我们需要寻找一种更高效的方法来解决这个问题。
2. 关键点
-
异或运算(XOR) :异或运算是位运算的一种,具有以下重要性质:
- a⊕a=0a⊕a=0:任何数与自身异或结果为0。
- a⊕0=aa⊕0=a:任何数与0异或结果为自身。
- 异或运算满足交换律和结合律,即 a⊕b⊕a=ba⊕b⊕a=b。
这些性质使得异或运算非常适合用于解决这类问题。通过遍历数组,将所有数字进行异或运算,相同的数字会相互抵消,最终剩下的结果就是那个唯一的数字。
3. 解决方案
- 初始化:定义一个变量
result,初始值为0。 - 遍历数组:对于数组中的每个数字,将其与
result进行异或运算。 - 返回结果:最终
result中存储的就是那个唯一的数字。
做题方式
-
初始化结果变量:
- 定义一个变量
result,初始值为0。这个变量将用于存储最终的结果。
- 定义一个变量
-
遍历数组:
- 使用增强型
for循环遍历数组中的每个元素num,并将num与result进行异或运算。异或运算的结果会保存回result。
- 使用增强型
-
返回结果:
- 遍历完成后,
result中存储的就是那个唯一的数字,返回result。
- 遍历完成后,
详细代码讲解
public class Main {
public static int solution(int[] inp) {
int result = 0;
for (int num : inp) {
result ^= num; // 使用异或运算
}
return result;
}
public static void main(String[] args) {
// 测试用例
System.out.println(solution(new int[]{1, 1, 2, 2, 3, 3, 4, 5, 5}) == 4); // true
System.out.println(solution(new int[]{0, 1, 0, 1, 2}) == 2); // true
System.out.println(solution(new int[]{7, 3, 3, 7, 10}) == 10); // true
}
}
代码解析
-
方法定义:
public static int solution(int[] inp):定义一个静态方法solution,接收一个整数数组inp作为参数,返回一个整数。
-
初始化结果变量:
int result = 0;:初始化一个变量result,初始值为0。这个变量将用于存储最终的结果。
-
遍历数组:
-
for (int num : inp) { result ^= num; }:使用增强型for循环遍历数组中的每个元素num,并将num与result进行异或运算。异或运算的结果会保存回result。 -
异或运算的解释:
- 假设数组为
[1, 1, 2, 2, 3, 3, 4, 5, 5],初始时result = 0。 - 第一次遍历:
result = 0 ^ 1 = 1 - 第二次遍历:
result = 1 ^ 1 = 0 - 第三次遍历:
result = 0 ^ 2 = 2 - 第四次遍历:
result = 2 ^ 2 = 0 - 第五次遍历:
result = 0 ^ 3 = 3 - 第六次遍历:
result = 3 ^ 3 = 0 - 第七次遍历:
result = 0 ^ 4 = 4 - 第八次遍历:
result = 4 ^ 5 = 1 - 第九次遍历:
result = 1 ^ 5 = 4
- 假设数组为
-
最终
result的值为4,即数组中唯一一个出现一次的数字。
-
-
返回结果:
return result;:遍历完成后,result中存储的就是那个唯一的数字,返回result。
-
测试用例:
System.out.println(solution(new int[]{1, 1, 2, 2, 3, 3, 4, 5, 5}) == 4);:测试用例1,输出true表示结果正确。System.out.println(solution(new int[]{0, 1, 0, 1, 2}) == 2);:测试用例2,输出true表示结果正确。System.out.println(solution(new int[]{7, 3, 3, 7, 10}) == 10);:测试用例3,输出true表示结果正确。
代码优化
-
时间复杂度:
- 该算法的时间复杂度为 O(n)O(n),因为我们需要遍历整个数组一次。
-
空间复杂度:
- 该算法的空间复杂度为 O(1)O(1),因为我们只使用了一个额外的变量
result来存储中间结果。
- 该算法的空间复杂度为 O(1)O(1),因为我们只使用了一个额外的变量
总结
通过使用异或运算,我们可以在 O(n)O(n) 时间复杂度和 O(1)O(1) 空间复杂度内找到数组中唯一一个出现一次的数字。这种方法不仅高效,而且简洁,非常适合解决这类问题。在做题过程中,我们可以常用右侧的ai功能,为我们提供思路,一道简单题思考五分钟左右依然毫无思路,就不要再浪费时间了,让ai给一些思路,刷题会更快。
扩展思考
-
多于一个唯一数字的情况:
- 如果数组中有多于一个唯一数字,如何找到所有的唯一数字?
- 一种方法是使用哈希表来记录每个数字的出现次数,然后再遍历哈希表找到出现次数为1的数字。但这会增加空间复杂度。
-
扩展到多个数组:
- 如果有多个数组,每个数组中都有一个唯一数字,如何高效地找到所有数组中的唯一数字?
- 可以考虑将所有数组合并成一个大数组,然后使用上述方法找到唯一数字。
-
实际应用:
- 这种方法在数据处理和算法竞赛中非常常见,尤其是在需要高效处理大量数据的情况下。
- 例如,在数据库查询优化中,可以利用类似的思想来快速找到唯一键值。
希望这些扩展思考能帮助你更深入地理解这个问题,并激发你在算法领域的探索兴趣。如果你有更多的问题或想法,欢迎随时交流!