一个数组,就一个数字出现1次或有两个数字都出现1次,其他他数字出现2次3次,求出出现1次的数

I 一个数组,就一个数字出现1次,其他出现2次

思路:采用异或^位运算,两个相同的数做异或,得到的结果是0,0与A异或得到A,那么把数组里面的数一起异或一遍,就会得到最后出现一次的数。

II 一个数组,两个不同的数字出现1次,其他出现2次

思路:仍然采用异或^位运算,两个相同的数做异或,得到的结果是0,0与C异或得到C,那么把数组里面的数一起异或一遍,那么最后就会得到 res = A异或B,也就是两个只出现1次的数的异或结果且非0,然后知道res中bit位任意出现1的位置就是A和B在这个bit位置 是不同造成(一个0一个1)的,因为其他数出现两次,在这个bit位置最后异或的结果是肯定是由A和B在这个位置不同造成的,接下来按照这个位置是0还是1对原数组进行分组异或,分别得到的值就是A和B。

II 一个数组,就一个数字出现1次,其他出现3次

思路:这个就很困难了,采用异或是无法完成的,走入死胡同。查资料小半天才明白别人的方法。对数的每个bit位1出现的次数模拟三进制加法,这样的话,那么对所有的数 进行相应bit位的1出现的次数进行三进制加法,最后就会归0,因为有一个数是出现1次,那么最后加法的结果就是这个数。
模拟三进制。00 01 10 11 代表 0 1 2 3. 这里是四个数是因为次数出现位11的时候我们就清0,11只是我们中间状态,进行判断清0的。那么就需要两个位来进行模拟
twos , ones (ones是低位, twos是高位) ,当twos , ones 同时为1说明这个bit位上的1出现了3次,就把该位清0,这样循环完所有数组,ones就是最后的结果

int singleNumber(vector<int> nums) {
       int size = nums.size();
       int ones = 0, int twos = 0;
       int threes=0;
       for(int i=0 ; i < size ;++i)
       {  //twos ^= (ones & nums[i])采用异或也可以,
          //因为ones & nums[i]为1的情况就只有相同的数出现了两次的时候。
          twos |= (ones & nums[i])//ones & nums[i]是获得是否产生进位
                                  //因为刚好二进制的话出现两个11 two=1了                                
                                  //1 0 twos就无法获得该进位 twos=0
          ones ^= nums[i]        //获得该低位的结果 如果为1^1,因为进位已经给了twos 所以ones = 0;
          threes = ~(twos&ones )//清0,因为两个位同时为1说明出现了3次,清0
          ones &= threes ;//清0出现3次的位
          twos &= threes ;//清0出现3次的位
       }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值