C语言/数据结构算法题:异或运算找出唯一出现一次的数字(O(n)时间+O(1)空间)
问题描述
在一个班级中,每位同学都拿到了一张卡片,上面有一个整数。有趣的是,除了一个数字之外,所有的数字都恰好出现了两次。现在需要你帮助班长小C快速找到那个拿了独特数字卡片的同学手上的数字是什么。
要求:
- 设计一个算法,使其时间复杂度为 O(n),其中 n 是班级的人数。
- 尽量减少额外空间的使用,以体现你的算法优化能力。
约束条件
- 1 ≤ cards.length ≤ 1001
- 0 ≤ cards[i] ≤ 1000
- 班级人数为奇数
- 除了一个数字卡片只出现一次外,其余每个数字卡片都恰好出现两次
代码如下:
#include <stdio.h>
int findUnique(int* cards, int cardsSize) {
int result = 0;
for (int i = 0; i < cardsSize; i++) {
result ^= cards[i];// 异或操作:相同为0,不同为1
}
return result;
}
int main() {
int cards1[] = {1, 1, 2, 2, 3, 3, 4, 5, 5};
int cards2[] = {0, 1, 0, 1, 2};
int cards3[] = {7, 3, 3, 7, 10};
printf("%d\n", findUnique(cards1, 9));
printf("%d\n", findUnique(cards2, 5));
printf("%d\n", findUnique(cards3, 5));
return 0;
}
运行结果
解题思路
核心思想:异或运算(XOR)
异或运算的性质:
交换律:
a ^ b = b ^ a结合律:
(a ^ b) ^ c = a ^ (b ^ c)自反性:
a ^ a = 0恒等性:
a ^ 0 = a
执行过程
对于数组{1, 1, 2, 2, 3, 3, 4, 5, 5}:
| 步骤 | 当前值 | result | 异或运算 |
|---|---|---|---|
| 初始 | — | 0 | — |
| 1 | 1 | 1 | 0 ^ 1 = 1 |
| 2 | 1 | 0 | 1 ^ 1 = 0 |
| 3 | 2 | 2 | 0 ^ 2 = 2 |
| 4 | 2 | 0 | 2 ^ 2 = 0 |
| 5 | 3 | 3 | 0 ^ 3 = 3 |
| 6 | 3 | 0 | 3 ^ 3 = 0 |
| 7 | 4 | 4 | 0 ^ 4 = 4 |
| 8 | 5 | 1 | 4 ^ 5 = 1 |
| 9 | 5 | 4 | 1 ^ 5 = 4 |
结果 = 4✅
复杂度分析
| 指标 | 值 |
|---|---|
| 时间复杂度 | O(n) — 只需遍历一次数组 |
| 空间复杂度 | O(1) — 只使用一个整数变量result |
关键规律:异或就是“无进位加法”
XOR(异或)在二进制中的本质是:
按位相加,但不进位。