问题描述
在一个班级中,每位同学都有一张卡片,上面写有一个整数。除了一个数字之外,所有的数字都恰好出现了两次。我们的任务是找到这个“独特的数字”,即唯一出现一次的数字。
要求:
- 设计一个算法,时间复杂度为 O(n)O(n)O(n),其中 nnn 是班级人数。
- 尽量减少额外空间使用。
思路解析
这个问题的关键在于如何高效找到唯一出现的数字。传统方法可能会想到排序或用哈希表统计频率,但这些方法都可能不满足空间优化或时间要求。
异或运算(XOR) 是解决此类问题的最佳工具。异或运算具有以下特性:
- 一个数与自身异或结果为 0(
a ^ a = 0)。 - 任何数与 0 异或结果为它本身(
a ^ 0 = a)。 - 异或运算满足交换律和结合律,即
(a ^ b) ^ c = a ^ (b ^ c)。
通过利用这些特性,可以得出以下结论:
-
将所有卡片数字进行异或操作,成对的数字会全部抵消为 0,唯一不重复的数字则会保留在结果中。
-
以下是实现此算法的代码: public class Main { public static int solution(int[] cards) { int result = 0; // 初始化结果为0 for (int card : cards) { result ^= card; // 每个数字与result异或 } return result; // 返回最终结果 }
public static void main(String[] args) { System.out.println(solution(new int[] { 1, 1, 2, 2, 3, 3, 4, 5, 5 }) == 4); // 测试 System.out.println(solution(new int[] { 0, 1, 0, 1, 2 }) == 2); // 测试 } } 代码解释:
solution方法初始化result为 0。- 通过
for循环遍历数组中的每个card,并用result ^= card将每个数字依次与result异或。 - 成对出现的数字会在异或过程中相互抵消(结果为 0),最终留下的
result就是唯一不重复的数字。 main方法中加入了测试用例,可以用来验证代码的正确性。
心得总结
- 异或的高效性:利用异或特性解决这类问题,不仅能将算法时间复杂度优化为 O(n)O(n)O(n),还能避免额外空间开销。
- 边界情况的考虑:算法简洁,适用于任何数组中有且仅有一个数字不重复的情况。
- 代码简洁:仅用几个行的代码实现目标,是算法设计中的一个经典技巧。