AcWing 74 数组中唯一只出现一次的数字

题目描述:

在一个数组中除了一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。你可以假设满足条件的数字一定存在。

思考题:

  • 如果要求只使用 O(n)的时间和额外 O(1)的空间,该怎么做呢?

样例

输入:[1,1,1,2,2,2,3,4,4,4]

输出:3

分析:

方法一:

统计各位1出现的次数。我们知道,如果没有那个出现了一次的数,其他数字都出现了三次。对于任意一个数,在计算机里存储的是32位二进制数,同样的数出现三次,则将这些数从0到31对应的位数统计一下,要么是0,要么必然是3的倍数。如果把出现一次的数x也统计进去呢,那么0-31某位上的1能够被3整除说明x对应位是0,否则就是1,这样就知道了所求数各位上是0还是1了。

class Solution {
public:
    int findNumberAppearingOnce(vector<int>& nums) {
        int b[32];
        memset(b,0,sizeof(b));
        for(int i = 0;i < 32;i++){
            for(auto x : nums){
                if(x >> i & 1)  b[i]++;
            }
        }
        int ans = 0,k = 1;
        for(int i = 0;i < 32;i++){
            if(b[i] % 3)    ans += k;
            k <<= 1;
        }
        return ans;
    }
};

方法二:

基于状态机求解。 

我们需要一种运算,与0做该运算不改变状态,与1做该运算三次则回到原状态。类似于一个长度为3的环,做三次运算会回到原点。设有两个数ones和twos,初始转态为零,记为(0,0),执行下面代码的操作,x=1,时,状态变为(1,0),再执行一次得到状态(0,1),在执行一次得到(0,0)。也就是经过三次操作回到原始状态。如果x为0呢,(0,0)变为(0,0),(1,0)变为(1,0),(0,1)变为(0,1),发现并不会改变状态。与方法一同理,各位执行三的倍数操作则会回到原点,再执行一次操作,x = 0则不改变状态,x = 1,则从(0,0)变为(1,0),这里的ones也就是我们所求的出现一次的数了。更具体一点,就是(0,0)与所有出现次数为3的数做该运算最后状态还是(0,0),再与出现一次的数(记为t)做该运算,t对应的位是0则不改变状态,是1则将ones对应的位置为1。

class Solution {
public:
    int findNumberAppearingOnce(vector<int>& nums) {
        int ones = 0,twos = 0;
        for(auto x : nums){
            ones = (ones ^ x) & ~twos;
            twos = (twos ^ x) & ~ones;
        }
        return ones;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值