在解决 “找单独的数” 这一问题时,我们的目标是在给定的整数数组中,找出那个仅出现一次的数,而其他数都恰好出现两次。
首先来探讨一下整体的解题思路。考虑到异或运算的特殊性质,对于任意两个相同的数进行异或操作,结果为 0。例如,5 ^ 5 = 0。基于此,如果我们对整个数组中的所有数依次进行异或操作,那么那些出现两次的数最终都会相互抵消,只剩下那个只出现一次的数。这就是解决本题的核心思想,巧妙地利用了异或运算的这种特性来简化问题的求解过程。
接下来详细解析一下代码:
public static int solution(int[] cards) {
int result = 0;
for (int card : cards) {
result ^= card;
}
return result;
}
在上述代码中,首先初始化一个变量result为 0。然后,通过一个增强型的for循环遍历输入的整数数组cards。在每次循环中,将当前的数组元素card与result进行异或操作,并将结果重新赋值给result。
当遍历到第一个数时,result就等于这个数本身,因为此时它是与 0 进行异或。接着,当遇到第二个数时,如果这个数与之前的数相同,根据异或的性质,它们异或的结果为 0,那么result就会变回 0;如果这个数与之前的数不同,result就会更新为这两个不同数的异或结果。随着循环的继续进行,每遇到一对相同的数,它们对result的影响就会相互抵消,最终result就会等于那个只出现一次的数。
例如,假设有数组[3, 3, 5, 5, 7]。首先,result初始为 0,当遇到第一个 3 时,result = 0 ^ 3 = 3。接着遇到第二个 3,result = 3 ^ 3 = 0。然后遇到第一个 5,result = 0 ^ 5 = 5,再遇到第二个 5,result = 5 ^ 5 = 0。最后遇到 7,result = 0 ^ 7 = 7,所以最终返回的result就是 7,也就是那个只出现一次的数。
从时间复杂度来看,代码中只进行了一次对数组的遍历,所以时间复杂度为 O(n),其中 n 是数组的长度,也就是班级的人数,满足题目要求。在空间复杂度方面,由于只使用了一个额外的变量result来存储异或结果,并没有使用与数组长度相关的额外数据结构来存储数据,所以额外空间复杂度非常低,仅为 O(1),这也很好地体现了算法在空间使用上的优化能力。这种算法简洁高效,充分利用了异或运算的特性,在处理此类 “找单独的数” 问题时具有很大的优势,无论是从时间效率还是空间利用的角度来看,都是一种较为理想的解决方案。