问题描述
在一个班级中,每位同学都拿到了一张卡片,上面有一个整数。有趣的是,除了一个数字之外,所有的数字都恰好出现了两次。现在需要你帮助班长小C快速找到那个拿了独特数字卡片的同学手上的数字是什么。
要求:
- 设计一个算法,使其时间复杂度为 O(n),其中 n 是班级的人数。
- 尽量减少额外空间的使用,以体现你的算法优化能力。
实现思路1
HashMap计数:使用哈希表计数的方法是通过一个哈希表来记录每个数字出现的次数。然后,我们遍历哈希表,找到出现次数为1的数字,这个数字就是唯一的数字。
算法步骤:
- 创建一个哈希表来存储数字及其出现次数
- 遍历数组,统计每个数字出现的次数
- 遍历哈希表,找到出现次数为1的数字
- 如果没有找到出现次数为1的数字,抛出异常
public static int findUniqueNumber(int[] cards) {
// 创建一个哈希表来存储数字及其出现次数
Map<Integer, Integer> countMap = new HashMap<>();
// 遍历数组,统计每个数字出现的次数
for (int num : cards) {
countMap.put(num, countMap.getOrDefault(num, 0) + 1);
}
// 遍历哈希表,找到出现次数为1的数字
for (Map.Entry<Integer, Integer> entry : countMap.entrySet()) {
if (entry.getValue() == 1) {
return entry.getKey();
}
}
// 如果没有找到出现次数为1的数字,抛出异常
throw new IllegalArgumentException("No unique number found");
}
实现思路2
异或运算:要解决这个问题,我们可以利用异或运算的性质。异或运算有一个特点:任何数和它自己异或的结果是0,任何数和0异或的结果是它本身。因此,如果我们对所有数字进行异或运算,成对的数字会相互抵消,最后剩下的就是那个没有配对的数字。x ^ x = 0,并且 x ^ 0 = x.
- 首先,我们需要对数组
cards中的所有数字进行异或运算。 - 我们从第一个数字开始,依次与后面的数字进行异或运算。
- 当我们遇到成对的数字时,它们会相互抵消,结果为0。
- 最后剩下的数字就是那个没有配对的数字。
例如:输入:cards = [1, 1, 2, 2, 3, 3, 4, 5, 5]
现在,让我们对给定的数组 cards = [1, 1, 2, 2, 3, 3, 4, 5, 5] 进行异或运算:
初始化res = 0.
0 ^ 1 = 0,0 ^ 1 = 0······0 ^ 4 = 4,4 ^ 5 ^ 5= 4
我们可以看到,1、2、3 和 5 都出现了两次,它们会相互抵消
输出:4
解释:拿到数字 4 的同学是唯一一个没有配对的。
算法步骤
- 初始化一个变量
result为 0。 - 遍历数组中的每一个数字,将
result与当前数字进行异或运算。 - 遍历结束后,
result就是那个单独的数字。
public static int solution(int[] cards) {
// Edit your code here
int result = 0;
for (int i : cards) {
result = result^i;
}
return result;
}
```