一起养成写作习惯!这是我参与「掘金日新计划 · 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
思路
- 数组非空 -> nums.length > 0
- 只有一个元素出现一次,其余每个元素均出现两次 -> 数组长度为 2n+1
- 要求不能使用额外空间
- 哈希表(最先想到的方法,但是会开辟新的空间与条件3冲突)
-
思路:
因为要找到只出现一次的元素,所以我们可以将数组元素放入集合中,因为集合只能存放一些相互独立的不重复的元素
-
具体步骤
-
创建一个set集合
-
遍历数组,判断该数组元素是否存在于集合中,若存在则在集合中删除这个数据,若不存在加入这个数据
-
将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]
};
-
排序 + 比较
-
思路:
-
因为拿到的是无序数组,没有规律性,所以可以将其先排好序
-
排好序后,相同的数组元素相邻,成对出现 -> 若nums[i + 1] - nums[i] !== 0 两个元素不等,其中有一个就是我们要找的只出现一次的元素
-
具体步骤:
- 将数组排序
- 拿到排好序后的数组, 遍历数组,令第 i+1 个元素和第 i 个元素相减得到的差值若大于0,返回 nums[i], 若差值等于0,说明这一对元素相等 则令 i++,让下次循环比较下一对数组元素
- 在完成上一步要求后,还需要做一些处理
// 防止数组越界 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];
};