题解:找单独的数 | 豆包MarsCode AI刷题

145 阅读4分钟

找到独特的数字卡片——位运算巧解重复数字问题

在一个班级中,每位同学都拿到了一张数字卡片。除了一个数字外,所有的数字都恰好出现了两次。我们的任务是帮助班长小C找到那个唯一没有配对的数字

一、问题分析

这个问题看似简单,但要在时间复杂度为 O(n)空间复杂度为 O(1) 的条件下解决,需要一些巧妙的思路。

1. 重复数字的特性

  • 成对出现:除了一个数字外,其余数字都出现了两次。
  • 唯一性:需要找到那个只出现一次的数字。

2. 常规解法的局限

  • 使用哈希表:可以记录每个数字出现的次数,但空间复杂度为 O(n)。
  • 排序后比较:时间复杂度为 O(n log n),不满足要求。

为满足题目要求,我们需要一种既能在 O(n) 时间内解决,又能将空间复杂度降到 O(1) 的方法。

二、解题思路

1. 利用异或运算

异或(XOR)操作的性质
  • 交换律:a ^ b = b ^ a
  • 结合律:a ^ (b ^ c) = (a ^ b) ^ c
  • 自反性:a ^ a = 0
  • 零元性:a ^ 0 = a
异或操作的应用
  • 成对抵消:两个相同的数字异或后为 0。
  • 累积结果:将所有数字异或,最终结果就是那个唯一的数字。

2. 算法步骤

  1. 初始化结果变量:设定一个变量 uniqueNumber = 0
  2. 遍历数组并异或:对于数组中的每个数字 num,执行 uniqueNumber ^= num
  3. 返回结果:遍历结束后,uniqueNumber 就是那个唯一的数字。

三、代码实现

public class Main { 
    public static int solution(int[] cards) {
        int uniqueNumber = 0;
        for (int num : cards) {
            uniqueNumber ^= num; // 异或操作,抵消成对的数字
        }
        return uniqueNumber;
    }

    public static void main(String[] args) {
        // 测试样例1
        int[] cards1 = {1, 1, 2, 2, 3, 3, 4, 5, 5};
        System.out.println("唯一的数字是:" + solution(cards1)); // 输出:4

        // 测试样例2
        int[] cards2 = {0, 1, 0, 1, 2};
        System.out.println("唯一的数字是:" + solution(cards2)); // 输出:2

        // 测试样例3
        int[] cards3 = {7, 3, 3, 7, 10};
        System.out.println("唯一的数字是:" + solution(cards3)); // 输出:10
    }
}

四、详细解释

1. 初始化结果变量

int uniqueNumber = 0;
  • 初始值为 0,因为 0 与任何数异或结果为该数本身。

2. 遍历数组并异或

for (int num : cards) {
    uniqueNumber ^= num;
}
  • 循环过程:依次将数组中的每个数字与 uniqueNumber 进行异或操作。
  • 异或结果更新:由于成对的数字会互相抵消,最终 uniqueNumber 中只会剩下那个唯一的数字。

3. 返回结果

return uniqueNumber;
  • 最终的 uniqueNumber 就是我们要找的数字。

五、示例演示

示例1:cards = [1, 1, 2, 2, 3, 3, 4, 5, 5]

步骤numuniqueNumber异或操作uniqueNumber
1100 ^ 1 = 11
2111 ^ 1 = 00
3200 ^ 2 = 22
4222 ^ 2 = 00
5300 ^ 3 = 33
6333 ^ 3 = 00
7400 ^ 4 = 44
8544 ^ 5 = 11
9511 ^ 5 = 44
  • 最终结果uniqueNumber = 4

示例2:cards = [0, 1, 0, 1, 2]

  • 过程类似,最终 uniqueNumber = 2

六、时间和空间复杂度分析

1. 时间复杂度:O(n)

  • 原因:只需遍历一次数组,执行 n 次异或操作。

2. 空间复杂度:O(1)

  • 原因:只使用了一个额外的变量 uniqueNumber,不依赖于输入规模。

七、扩展思考

1. 为什么异或能找到唯一的数字?

  • 异或的抵消特性:相同的数字异或后为 0,不同的数字异或后保留信息。
  • 累积结果:经过异或操作,所有成对的数字被抵消,只剩下那个唯一的数字。

2. 异或操作的其他应用

  • 交换两个变量而不使用临时变量
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;
    
  • 检测两个数的奇偶性是否相同(a ^ b) & 1

3. 如果数字出现的次数不同怎么办?

  • 如果其他数字出现的次数不是两次,而是三次、四次,或者出现次数不定,那么需要使用其他算法,例如位运算统计每一位上的 1 的个数。

八、总结

通过巧妙地利用异或运算的性质,我们在满足时间和空间要求的情况下,成功地找到了数组中唯一不重复的数字。这种位运算的方法在处理成对出现的问题时,非常高效且简洁。

  • 优势:算法简洁,易于实现,性能高效。
  • 适用范围:适用于数组中除了一个数字外,其他数字都出现偶数次的情况。

注意事项

  • 数据范围:确保数字在整数范围内,避免溢出。
  • 特殊情况:如果数组为空或不满足题目条件,需要进行异常处理。