返回

剖析算法:只出现一次的数字 III

前端

算法概述

给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。我们的目标是找出只出现一次的那两个数字。我们首先定义了两种情况:

  • 情况一: 两个只出现一次的数字的符号不同。
  • 情况二: 两个只出现一次的数字的符号相同。

针对不同的情况,我们需要分别采用不同的算法来解决。

情况一:两个只出现一次的数字的符号不同

算法步骤:

  1. 对数组 nums 进行异或运算,记为 resultresult 是两个只出现一次的数字的异或结果。
  2. result 中找到任意一个为 1 的二进制位,记为 mask
  3. 再次对数组 nums 进行异或运算,这次只考虑那些二进制位为 mask 的数字,记为 x
  4. x 中找出任意一个为 1 的二进制位,记为 y
  5. xy 就是只出现一次的那两个数字。

算法复杂度:

时间复杂度:O(n),其中 n 是数组 nums 的长度。
空间复杂度:O(1),不需要额外的空间。

情况二:两个只出现一次的数字的符号相同

算法步骤:

  1. 对数组 nums 进行排序。
  2. 遍历数组 nums,如果发现相邻的两个数字不相等,则这两个数字就是只出现一次的数字。

算法复杂度:

时间复杂度:O(n log n),其中 n 是数组 nums 的长度。
空间复杂度:O(1),不需要额外的空间。

代码示例

/**
 * 给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。找出只出现一次的那两个数字。
 *
 * 示例 1:
 * 输入:nums = [1,2,1,3,2,5]
 * 输出:[3,5]
 * 解释:只出现一次的数字是 3 和 5。
 *
 * 示例 2:
 * 输入:nums = [-1,0]
 * 输出:[-1,0]
 * 解释:只出现一次的数字是 -1 和 0。
 *
 * 示例 3:
 * 输入:nums = [0,1]
 * 输出:[0,1]
 */
const singleNumberIII = (nums) => {
  // 第一次异或运算,找出两个只出现一次的数字的异或结果
  let result = 0;
  for (let num of nums) {
    result ^= num;
  }

  // 找到任意一个二进制位为 1 的数字
  let mask = result & (-result);

  // 第二次异或运算,找出只出现一次的那两个数字
  let x = 0;
  for (let num of nums) {
    if ((num & mask) > 0) {
      x ^= num;
    }
  }

  let y = result ^ x;

  return [x, y];
};

总结

在本文中,我们探讨了如何找出数组中只出现一次的那两个数字。我们介绍了两种情况:两个只出现一次的数字的符号不同和两个只出现一次的数字的符号相同。针对不同的情况,我们分别介绍了相应的算法来解决。我们还提供了代码示例来帮助您更好地理解这些算法。希望这篇文章能对您有所帮助!