LeetCode | Single Number II(单个数字II)

Given an array of integers, every element appears three times except for one. Find that single one.

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

题目解析:

除了一个数只出现一次以外,其他元素都出现了三次。

这道题目比较难,比较普遍的方式是,建立哈希表,统计每一个元素出现的次数,然后再返回个数为1的元素。

但是题目中要求,只能用常量空间,不能这样做。


方案一:

类似哈希,我们可以通过记录元素的某一位的个数,既然都出现三次,则其对应的位为3的倍数。求出以后,对所有为mod 3就行了。得到的是最后要找的数据。

class Solution {
public:
    int singleNumber(int A[], int n) {
        int bitnum[32]={0};
        int res=0;
        for(int i=0; i<32; i++){
            for(int j=0; j<n; j++){
                bitnum[i]+=(A[j]>>i)&1;
            }
            res|=(bitnum[i]%3)<<i;
        }
        return res;
    }
};

这里是以位为主循环,一次求所有数据的某一位的个数。然后对res或运算。

时间:O(32*N),这是一个通用的解法,如果把出现3次改为 k 次,那么只需模k就行了。


方案二:

利用三个变量one,two,three。

one的位表示只出现了一次,two的位表示出现了两次,那么three = two & one就表示为1的位已经出现了三次。那么最后将one和two中对应的位清零。

当然函数进入的时候,先通过two |= one & a[i]计算所有出现两次的位。结合上面说的one中的位值出现了1次,和a[i]相与后,得到了当前已经出现了两次的位。当然由于two是或的,可能已经有包含的1,则该位就出现了四次。先往下走。

然后是one = one ^ a[i];由于已经把都为1的值保存在two中,这里也就清掉了为one和a[i]中都为1的位。但如果one的第k位为0,a[i]的第k位也为0,会将one置为1。这也无妨当出现a[i]为3个的时候,会将该k位清除的。

流程:

1、更新two |= one & a[i]

2、更新one ^= a[i]

3、更新three = one & two

4、清除one和two已经满足3个的位:one &= ~three;two &= ~three

class Solution {
public:
    int singleNumber(int A[], int n) {
        int one=0, two=0, three=0;
        for(int i=0; i<n; i++){
            two |= one&A[i];
            one^=A[i];
            //cout<<one<<endl;
            three=one&two;
            one&= ~three;
            two&= ~three;
        }
        return one;
    }
};

点赞