找单独的数
问题描述
在一个班级中,每位同学都拿到了一张卡片,上面有一个整数。有趣的是,除了一个数字之外,所有的数字都恰好出现了两次。现在需要你帮助班长小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
- 班级人数为奇数
- 除了一个数字卡片只出现一次外,其余每个数字卡片都恰好出现两次
Code:
// 核心逻辑:通过异或运算找出数组中只出现一次的数字
public static int solution(int[] inp) {
// 初始化结果变量为0,所有数字会与它逐步异或
int result = 0;
// 遍历数组,使用异或运算抵消成对出现的数字
for (int p : inp) {
result ^= p; // 异或当前数字
}
// 返回最终结果,即只出现一次的数字
return result;
}
public static void main(String[] args) {
// 测试用例,验证算法的正确性
System.out.println(solution(new int[]{1, 1, 2, 2, 3, 3, 4, 5, 5}) == 4); // 数组中唯一的数字是4
System.out.println(solution(new int[]{0, 1, 0, 1, 2}) == 2); // 数组中唯一的数字是2
}
}
示例流程
假设输入数组为 {1, 1, 2, 2, 3, 3, 4}:
-
初始状态:
result = 0。 -
遍历过程:
- 第1步:
result = 0 ^ 1 = 1 - 第2步:
result = 1 ^ 1 = 0(第一个1与第二个1被抵消) - 第3步:
result = 0 ^ 2 = 2 - 第4步:
result = 2 ^ 2 = 0(两个2被抵消) - 第5步:
result = 0 ^ 3 = 3 - 第6步:
result = 3 ^ 3 = 0(两个3被抵消) - 第7步:
result = 0 ^ 4 = 4(最终保留4)
- 第1步:
-
输出:
4
一.思路介绍
- 代码功能说明
这段代码的功能是:
- 找出一个整数数组中只出现一次的元素,假设数组中只有一个这样的元素,其它元素均出现两次。
- 代码通过异或运算实现这一目标,使用的是位操作的特性。
2. 核心算法思路
异或运算 ^ 是位运算中的一种。其特点如下:
- 交换律:
a ^ b == b ^ a - 结合律:
(a ^ b) ^ c == a ^ (b ^ c) - 自身异或为零:
a ^ a == 0 - 零与任意数异或为数本身:
a ^ 0 == a
基于以上特性:
- 如果数组中的数字按位异或,成对出现的数字会抵消为
0,因为a ^ a = 0。 - 最终结果只剩下那个只出现一次的数字。
实现流程:
- 初始化
result = 0。 - 遍历数组,将每个数字与
result进行异或。 - 遍历完成后,
result即为数组中只出现一次的数字。
二. 总结
-
效率:
这段代码的时间复杂度为 O(n) ,因为只需要一次遍历数组。
空间复杂度为 O(1) ,无需额外的数据结构存储中间结果。相较于哈希表或集合记录频次的方法,这种方案非常高效。 -
简洁性:
利用异或运算的数学特性,代码非常简洁。避免了复杂的条件判断或额外的数据结构操作。 -
边界情况的处理:
代码对边界情况天然适应,例如:- 数组中只有一个数字(直接返回该数字)。
- 所有数字均成对出现(结果为 0)。
三.个人理解
-
选择异或运算的优越性:
- 异或运算的特性非常适合这种“一对一抵消”的场景。
- 时间复杂度是 O(n) ,只需要遍历一次数组,非常高效。
- 空间复杂度是 O(1) ,不需要额外的数据结构,比用哈希表记录数字频次更节约资源。
-
与其他方法的对比:
-
如果不用异或运算,也可以用其他方法,如:
- 哈希表:记录每个数字的出现次数,最后找到频次为 1 的数字。但哈希表需要额外的存储空间,空间复杂度为 O(n) 。
- 排序:对数组排序,然后找出唯一未成对的数字。排序的时间复杂度为 O(n log n) 。
-
异或运算是最优解之一,尤其适合大规模数据或嵌入式环境。
-
-
适用范围:
- 当前方法假设数组中只有一个数字是单独出现,其余数字成对出现。如果有多个独立数字或者出现三次以上的数字,这种方法就无法解决问题,需要改用其他算法(如位运算的分组法)。
-
通用性与扩展性:
-
这种算法思路不仅限于查找单个唯一数字,还可以扩展到其他问题。例如:
- 找出两个唯一数字:通过分组异或来解决。
- 检查数据完整性:异或操作常被用作校验码的一部分。
-