每日一题|只出现一次的数字

44 阅读2分钟

给定一个非空整数数组,除了某个元素只出现了一次,其余元素均出现两次。找出只出现了一次的数组。

方法1

    const uniqueNum = (nums) {
        const numsGroup = nums.map(num => nums.filter(
        v => v === num));
        return numsGroup.find(num => num.length === 1)[0]
    }

思路:

  • 使用map遍历数组
  • 使用filter再次遍历,最终会得到一个二维数组
  • 查找二维数组中长度为1的元素,取当前元素的第0个即可得到目标元素

复杂度分析

  • 时间复杂度:map嵌套filter做了两次遍历,时间复杂度为O(n2n^2),find只做了一次遍历,复杂度为O(n),所以最终的时间复杂度是O(n2n^2)
  • 空间复杂度:
    • numsGroup 数组会存储 n 个子数组
    • 每个子数组的长度等于原数组中对应元素的出现次数(至少1次,最多 n 次)
    • 最坏情况(所有元素相同):每个子数组长度为 n ,总空间为 n * n = n²
    • 平均情况(其他元素出现2次,仅1个元素出现1次):空间为 (n-1)*2 + 1 = 2n-1 ,仍属于 O(n) (但最坏情况是 O(n²) )
  • 最终的时间复杂度和空间复杂度都为O(n2n^2)

方法2

    const uniqueNum = (nums: number[]): number => {
      let result = 0;
      for (const num of nums) {
        result ^= num; // 等价于 result = result ^ num
      }
      return result;
    }

思路

  • 遍历数组,使用异或进行判断,异或的特性为相同数字异或结果为0;
  • 当前数组进行异或判断之后只有目标元素不为0; 复杂度分析
  • 时间复杂度:O(n),数组仅遍历一次,因此复杂度为O(n);
  • 空间复杂度:O(1),只有result声明了一次常数级额外空间;

方法3

    const uniqueNum = (nums: number[]): number => {
      return nums.filter(num => {
          nums.indexOf(num) === nums.lastIndexOf(num)
      })[0];
    }

思路

  • 使用filter过滤当前数组中第一个下标和最后一个下标一样的数组,产生一个新的数组;
  • 只有唯一出现的数组两次下标一致,取第0个元素即可; 复杂度分析
  • 时间复杂度:O(n2n^2),indexOf需要遍历两次数组,因此复杂度为O(n2n^2);
  • 空间复杂度:O(1),声明了一次常数级额外空间;

总结 从复杂度和代码实现上来看,异或的方式为最优选,复杂度也是最小的。