问题描述
在一个班级中,每位同学都拿到了一张卡片,上面有一个整数。有趣的是,除了一个数字之外,所有的数字都恰好出现了两次。现在需要你帮助班长小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
- 班级人数为奇数
- 除了一个数字卡片只出现一次外,其余每个数字卡片都恰好出现两次
问题分析
这道题说的是在一堆成对出现的数中找出唯一的单独的数。是一道非常简单的题,这里给大家提供两种思路。
方法一:哈希表
这是一种非常直接的方法,直接用哈希表记录每个数字出现的次数然后找出出现次数为1的数字就可以了。这个表中key是具体的数字,value是每个数字出现的次数。下面是详细步骤:
1.初始化哈希表
先创建一个哈希表用来存储每个数字和每个数字出现的次数。
2.遍历这个数组并且更新哈希表
遍历这个数组,对于每个数字,如果它不在哈希表中则将它添加到表中,并且将其出现次数设置为1。 如果已经存在表中,就将其出现次数加1。
3.找出单独的数
再次遍历哈希表,找到value为1的数字,这个数就是单独的数。
代码示例
int solution(std::vector<int> cards) {
std::unordered_map<int, int> countMap;
// 遍历所有数字,更新哈希表中对应数字的计数
for (int num : cards) {
countMap[num]++;
}
// 遍历哈希表,找到出现次数为1的数字
for (const auto& pair : countMap) {
if (pair.second == 1) {
return pair.first;
}
}
return -1; // 如果没有找到,返回-1
方法二:异或
第二种方法更加简单且高效,我们可以使用异或^来找到单独的数。如果大家忘了什么是异或,下面我来给大家简单介绍一下异或的特点。
异或的运算规则是相同为0,不同为1,即\
1 ^ 1 = 0
0 ^ 0 = 0
1 ^ 0 = 1
异或性质
交换律: A ^ B = B ^ A
结合律: ( A ^ B ) ^ C = A ^ ( B ^ C )
自反性: A ^ B ^ B = A (由结合律可推: A ^ B ^ B = A ^ ( B ^ B ) = A ^ 0 = A)
根据异或的特性,我们只需要将数组遍历,遇到相同的数时变为0,遇到单独数字时变成该数字,最后仅剩下单独数字。是不是非常巧妙呢。
代码示例
int solution(std::vector<int> inp) {
int result = 0;
for (int i=0; i < inp.size(); i++)
{
result ^= inp[i];
}
return result;
}