找单独的数|豆包MarsCode AI刷题
题目描述
在一个班级中,每位同学都拿到了一张卡片,上面有一个整数。有趣的是,除了一个数字之外,所有的数字都恰好出现了两次。现在需要你帮助班长小C快速找到那个拿了独特数字卡片的同学手上的数字是什么。
要求:
- 设计一个算法,使其时间复杂度为 O(n),其中 n 是班级的人数。
- 尽量减少额外空间的使用,以体现你的算法优化能力。
解题思路
-
理解问题:
- 题目要求我们找到数组中唯一一个出现一次的数字。
- 数组中的其他数字都出现了两次。
-
数据结构选择:
- 由于我们需要在 O(n) 时间内完成,并且尽量减少额外空间的使用,可以考虑使用位运算。
-
算法步骤:
- 使用异或运算(XOR)来解决这个问题。异或运算有一个特性:
a ^ a = 0和a ^ 0 = a。因此,如果我们将数组中所有数字进行异或运算,最终结果就是那个唯一的数字。
- 使用异或运算(XOR)来解决这个问题。异或运算有一个特性:
图解
假设我们有以下数组:cards = [1, 1, 2, 2, 3, 3, 4, 5, 5]
-
初始化
result = 0。 -
遍历数组中的每一个元素,并对
result进行异或运算:result = 0 ^ 1 = 1result = 1 ^ 1 = 0result = 0 ^ 2 = 2result = 2 ^ 2 = 0result = 0 ^ 3 = 3result = 3 ^ 3 = 0result = 0 ^ 4 = 4result = 4 ^ 5 = 1result = 1 ^ 5 = 4
最终 result 的值为 4,即唯一的数字。
代码详解
public class Main { public static int solution(int[] inp) { if (inp == null || inp.length == 0) { throw new IllegalArgumentException("输入数组不能为空"); }
int result = 0;
for (int num : inp) {
result ^= num;
}
return result;
}
public static void main(String[] args) {
System.out.println("Test case 1: " + (solution(new int[]{1, 1, 2, 2, 3, 3, 4, 5, 5}) == 4));
System.out.println("Test case 2: " + (solution(new int[]{0, 1, 0, 1, 2}) == 2));
System.out.println("Test case 3: " + (solution(new int[]{7, 3, 3, 7, 10}) == 10));
System.out.println("Test case 4: " + (solution(new int[]{1}) == 1));
}
}
-
输入检查:
- 在
solution方法中,首先检查输入数组是否为空或长度为0,如果是,则抛出异常。
- 在
-
异或运算:
- 初始化
result为 0。 - 遍历数组中的每一个元素,并对
result进行异或运算。
- 初始化
-
返回结果:
- 最终
result就是那个唯一的数字。
- 最终
-
测试用例:
- 在
main方法中,添加了多个测试用例,包括边界情况(只有一个元素的数组),以确保代码的正确性。
- 在
知识点总结
-
异或运算(XOR) :
- 异或运算的特性:
a ^ a = 0和a ^ 0 = a。 - 通过异或运算,可以将数组中出现两次的数字相互抵消,最终剩下的就是唯一的数字。
- 异或运算的特性:
-
时间复杂度:
- 该算法的时间复杂度为 O(n),其中 n 是数组的长度。
-
空间复杂度:
- 该算法的空间复杂度为 O(1),因为我们只使用了一个额外的变量
result。
- 该算法的空间复杂度为 O(1),因为我们只使用了一个额外的变量
学习建议
-
理解异或运算:
- 异或运算在解决一些特定问题时非常高效,尤其是在处理重复元素的问题时。建议深入理解异或运算的特性,并尝试在其他问题中应用。
-
练习边界情况:
- 在编写代码时,务必考虑边界情况,如空数组、只有一个元素的数组等。这有助于提高代码的健壮性。
-
多做练习:
- 通过多做类似的题目,可以更好地掌握位运算和其他优化技巧。建议在 LeetCode、Codeforces 等平台上寻找类似的题目进行练习。
-
代码风格:
- 保持良好的代码风格,如适当的注释、清晰的变量命名等,有助于提高代码的可读性和可维护性。