「前端刷题」136.只出现一次的数字(EASY)

88 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第16天,点击查看活动详情

题目(Single Number)

链接:https://leetcode-cn.com/problems/single-number
解决数:2999
通过率:72.1%
标签:位运算 数组 
相关公司:amazon bytedance microsoft 

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

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:

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

示例 2:

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

思路

  1. 数组非空 -> nums.length > 0
  2. 只有一个元素出现一次,其余每个元素均出现两次 -> 数组长度为 2n+1
  3. 要求不能使用额外空间
  • 哈希表(最先想到的方法,但是会开辟新的空间与条件3冲突)
    • 思路:

      因为要找到只出现一次的元素,所以我们可以将数组元素放入集合中,因为集合只能存放一些相互独立的不重复的元素

    • 具体步骤

    1. 创建一个set集合

    2. 遍历数组,判断该数组元素是否存在于集合中,若存在则在集合中删除这个数据,若不存在加入这个数据

    3. 将set集合转成数组返回数组第一个元素

    • 时间复杂度 O(n) 空间复杂度 O(n)

    • 代码:

var singleNumber = function (nums) {
   let set = new Set()
   for (let num of nums) {
    // 如果集合中存在此数据则删除说明该数据重复
			if (set.has(num)) set.delete(num)
			else set.add(num)
  }

  return num = Array.from(set)[0]

};
  • 排序 + 比较

    • 思路:

    1. 因为拿到的是无序数组,没有规律性,所以可以将其先排好序

    2. 排好序后,相同的数组元素相邻,成对出现 -> 若nums[i + 1] - nums[i] !== 0 两个元素不等,其中有一个就是我们要找的只出现一次的元素

    • 具体步骤:

    1. 将数组排序
    2. 拿到排好序后的数组, 遍历数组,令第 i+1 个元素和第 i 个元素相减得到的差值若大于0,返回 nums[i], 若差值等于0,说明这一对元素相等 则令 i++,让下次循环比较下一对数组元素
    3. 在完成上一步要求后,还需要做一些处理
    // 防止数组越界
    i < nums.length - 1 
    
    // 当只出现一次的元素是最后一个数组元素时,就要进行判断
    if(nums[i + 1] - nums[i] == 0 && i + 1 == nums.length - 2)
    
    // 防止只出现一次的元素出现在数组最后,但程序依然执行 i++的操作
    if(nums[i + 1] - nums[i] == 0 && i + 1 !== nums.length - 2)
        
    
    • 时间复杂度 O(n) 空间复杂度 O(1)

    • 代码:

var singleNumber = function (nums) {
  //  先将数组排好序
  nums = nums.sort((a, b) => a - b)

  if (nums.length == 1) {
    return nums[0]
  }
  // 遍历数组
  for (let i = 0; i < nums.length - 1; i++) {
    if (nums[i + 1] - nums[i] > 0) return nums[i]
    else if (nums[i + 1] - nums[i] == 0 && (i + 1) !== (nums.length - 2)) i += 1
    else if (nums[i + 1] - nums[i] == 0 && (i + 1) == (nums.length - 2)) return nums[nums.length - 1]
  }
};
  • 异或

    • 思路:

      因为需要找到只出现一次的元素,正好符合异或的运算

      异或运算是对 0和数据的二进制位进行运算 0 ^ 0 = 0; 0 ^ 1 = 1; 1 ^ 1 = 0; 1 ^ 0 = 0,相同的数进行异或运算后为0,且异或运算满足交换律和结合律

      • 例:将数组[4, 1, 2, 1, 2]的第一项与之后的元素进行位运算

      4^1^2^1^2 = 100 -> 101 -> 111 -> 110 -> 100 = 4

      化简后可得

      4^(1^1)^(2^2) = 100 = 4

    • 时间复杂度 O(n) 空间复杂度 O(1)

    • 代码:

var singleNumber = function (nums) {
	// 遍历数组
  for (let i = 1; i < nums.length; i++) {
		// 从第一个数组元素开始进行异或运算 
    nums[0] ^= nums[i];
    console.log(nums[0]);
  }
  return nums[0];
};