/** 方法一:哈希表 * @param {number[]} nums * @return {number} */ var singleNumber = function(nums) { let map = new Map(); let res; for(let num of nums){ freq.set(num, (freq.get(num)||0) +1 ) } for(let [m,c] of map){ if(c==1){ res = m; break; } } return res; }; /** 方法二:依次确定每一个二进制位 * @param {number[]} nums * @return {number} */ var singleNumber = function(nums) { let res = 0; for(let i = 0;i<32;i++){ let total = 0; for(let num of nums){ total += (num>>i)&1; } if(total%3 != 0){ res |= 1<<i; } } return res; }; let nums = [2,2,3,2] console.log(nums, singleNumber(nums)) nums =[0,1,0,1,0,1,99] console.log(nums, singleNumber(nums)) /** 状态机2 * @param {number[]} nums * @return {number} */ var singleNumber = function(nums) { let a = 0,b=0; for(let num of nums){ let aNext = ~a&b&num|a&~b&~num; let bNext = ~a&~b&num|~a&b&~num; a = aNext; b = bNext; } return b; };
状态机2来推导公式:
3 种状态 存储 输入 结果 ab c ab 00 1 01 01 1 11 (注意这个地方a是1),所以a= ~a&b&c 11 1 0000 0 00 01 0 01 11 0 11 (注意这个地方a是1),所以a=a&b&~c 我们看到有两个地方a是1,所以 a= ~a&b&c|a&b&~c,如果abc那个是1我们就用原来的字符表示,如果是0就取反,多个是1的地方用运算符|表示。
00 1 01 ~a & ~b & c 01 1 11 ~a & b & c 01 0 01 ~a & b & ~c 11 0 11 a & b & ~c 所以b=~a & ~b & c | ~a & b & c | ~a & b & ~c | a & b & ~c。
// 提示: // 1 <= nums.length <= 3 * 104 // -231 <= nums[i] <= 231 - 1 // nums 中,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次
// 进阶:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?