137. Single Number II 只出现一次的数字II 解法

题目描述如下:

Given a non-empty array of integers, every element appears three times except for one, which appears exactly once. Find that single one.

Note:

Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

Example 1:

Input: [2,2,3,2]
Output: 3

Example 2:

Input: [0,1,0,1,0,1,99]
Output: 99

数组里除了一个数字外其他都出现了3次,找出该出现一次数字

不动脑的简单解法很简单,

用map之类的一次遍历统计出现次数,再遍历map筛出出现次数为1的那个数字。但该方法用了额外的存储空间

int singleNumber(vector<int>& nums) {
        map<int,int>dict;
        for(auto i : nums)
        {
            if(dict.find(i)!=dict.end())
                ++dict[i];
            else
                dict[i]  = 1;
            
        }
        for(auto beg = dict.begin();beg!=dict.end();++beg)
        {
            if(beg->second == 1)
                return beg->first;
        }
        return 0;
    }

做一次原地排序,比较一下左右两个数字和自己的相等关系,某个数字左右都不和自己相同显然就是了,但该方法时间复杂度并不是线性

int singleNumber(vector<int>& nums) {
       sort(nums.begin(),nums.end());
        if(nums[0]!= nums[1])
            return nums[0];
        if(nums[nums.size()-1] != nums[nums.size()-2])
            return nums[nums.size()-1];
//边界判断
        
        for(int i = 1; i < nums.size()-1;++i)
        {
            if(nums[i]!=nums[i-1]&& nums[i]!=nums[i+1])
                return nums[i];
        }
        
    }

 

以上2个方法显然不是该题目所要考察的,该题目希望考察的是位运算,回顾该系列题目的第一道,题目要求变成其他的变成了2次,第一道的做法是 挨个进行亦或,其原理是相同的数字进行亦或就为0,而任何数字和0亦或为原先的数字。

显然该题好像和亦或没什么关系,但带来了启示,其做法应该是与每个数字的位有关。

该题目所用int应为32位的整型,那么有 以  3  5 5 5 为例,

该4个数的2进制为:

0011

0101

0101

0101

从最低位看,4个数的最低为count 为4,第二位为 1,第三位2,第四位为0,若count%3 != 0,就把该为作为结果位的答案的话,结果就为: 0011,正好就是我们所需要筛出来的答案

 

为何?其原理就是在某个位上,该位上的count自然要么 为3N,或3N+1(N代表重复的数),若为3N自然表示出现在该位的都是重复数字,3N+1中的那个1就是不重复的,代码如下:

int singleNumber(vector<int>& nums) {
        
        int result = 0;
        
        for(int i = 0; i <32;++i)
        {
            int mask = 1<<i; //从最低位,挨个筛出相应位
            int count = 0;
            
            for(auto num : nums)
            {
                if((num&mask) != 0 )
                    ++count;
            }
            
            if(count%3==1)
                result |= mask;  //结果的相应位就置为1
            
            
                
        }
        return result;
    }

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值