quejing
发布于 2024-02-28 / 236 阅读
0

只出现一次的数字

难度:简单

1. 题干

给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。

示例1:

输入:nums = [2,2,1]
输出:1

示例2:

输入:nums = [4,1,2,1,2]
输出:4

示例3:

输入:nums = [1]
输出:1

提示

  • 1 <= nums.length <= 3 * 104
  • -3 * 104 <= nums[i] <= 3 * 104
  • 除了某个元素只出现一次以外,其余每个元素均出现两次。

2. 思路

很快能想到的一个思路是:按顺序取其中的一个数,然后和其他的数字做对比,看看是否相等,如果存在相等的情况,则表示这个数不是唯一的,对比下一个数字,直到找到那个唯一数字。
伪代码如下:

// 伪代码,未测试是否能够正常编译与执行,仅做逻辑分析
int only_num(int *nums, int size)
{
    int i,j;
    for (i = 0; i < size; i++) { // 遍历所有的数字,取其中的第i个数字
      for (j = 0; j < size; j++) { // 按顺序与其他数字比较
        if (i == j) // 不和自身比较
          continue;
        if (nums[i] == nums[j])  // 存在与第i个数字相等的情况,说明当前数字不唯一,跳出,取第i个数字的下一个进行比较
          break;
      }
      if (j >= size) // 当 j 达到size大小时,说明和所有数字都进行了比较,未找到相同的数字,说明此时的第i个数字是我们所需要的
        break;
    }
    return nums[i]; // 返回第i个数字
}

上面的逻辑,空间复杂度上,只定义了i和j两个变量,所以空间复杂度是O(1)

时间复杂度

  • 在最好的情况下(第一个就是唯一的数字),此时程序外层循环执行了1次,内层循环执行了n次,所以时间复杂度是O(n);
  • 当考虑到最差情况(最后一个数字才是唯一数字),此时外层循环执行了n次,内层循环可能执行的次数是0~n次,所以总体来说大概是O(n2);

时间复杂度是不满足题干要求的(题干要求线性时间复杂度)。

再认真阅读题目,其中有提示说 其余每个元素均出现两次,这就想到了异或的操作:两个相等的数做异或操作后,值为0,任何数和0做异或操作后为原来的数,即:

a ^ b ^ b = b ^ b ^ a = a;
a ^ b ^ c ^ b ^ c = a;

所以最终代码可以写成:

int only_num(int *nums, int size)
{
    int n = nums[0];
    for (i = 1; i < size; i++) {
      n ^= nums[i];
    }
    return n;
}