题目
给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。
示例 1 :
输入:nums = [2,2,1] 输出:1
示例 2 :
输入:nums = [4,1,2,1,2] 输出:4
示例 3 :
输入:nums = [1] 输出:1
解法一:hash
很自然地会想到用hash表来解题,先上hash的方法(我写得不是很优雅)
/**
* @param {number[]} nums
* @return {number}
*/
var singleNumber = function(nums) {
let map = new Map();
nums.forEach(el => {
if (!map.has(el)) {
map.set(el, 1);
} else {
map.set(el, map.get(el) + 1);
}
})
for(const [key, value] of map) {
if (value === 1) {
return key;
}
}
};
其中还遇到了一些坑,我在map.set(el, map.get(el) + 1)这一步原来是写成map.set(el, map.get(el)++)报错了。
为什么呢?
在 JavaScript 中,++ 运算符用于递增一个变量的值,并将递增后的结果赋值给该变量。
然而,map.get(element) 返回的是一个值,而不是一个变量,因此不能直接使用 ++ 运算符进行递增操作。
解法二:异或
第二种方法是看leetcode上别人的解法,用异或运算,顺便学一学优雅的解法。
首先得先知道异或运算的规则。
异或运算是一种逻辑运算,通常用符号 "XOR" 表示。
在布尔代数中,异或运算的结果为真(1),当且仅当操作数中恰好有一个为真时。换句话说,如果两个操作数相同则结果为假(0),如果两个操作数不同则结果为真(1)。
具体来说,如果将两个操作数记为 A 和 B,则异或运算的真值表如下:
- A XOR B = 0 (false) 当 A = 0 且 B = 0,或者 A = 1 且 B = 1
- A XOR B = 1 (true) 当 A = 0 且 B = 1,或者 A = 1 且 B = 0
这是异或运算的基本特性
但解这道题的关键不在于这个,而是在于下面这些隐藏规则:
- 一个数和 0 做 XOR 运算等于本身:a⊕0 = a
- 一个数和其本身做 XOR 运算等于 0:a⊕a = 0
- XOR 运算满足交换律和结合律:a⊕b⊕a = (a⊕a)⊕b = 0⊕b = b
所以这题的解为
/**
* @param {number[]} nums
* @return {number}
*/
var singleNumber = function(nums) {
let ans = 0;
for(const num of nums) {
ans ^= num;
}
return ans;
};