137. 只出现一次的数字 II

// 给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。
/** 方法一:哈希表
 * @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     00

 

   00      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的地方用运算符|表示。



再比如有4个地方b是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 = [2,2,3,2]
// 输出:3
// 示例 2:
// 输入:nums = [0,1,0,1,0,1,99]
// 输出:99 

 

// 提示:
// 1 <= nums.length <= 3 * 104
// -231 <= nums[i] <= 231 - 1
// nums 中,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 

 

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

 

posted @ 2021-05-24 18:32  尖子  阅读(85)  评论(0编辑  收藏  举报