code第一部分数组:第二十三题 奇数次中查找单独出现一次的数

code第一部分数组:第二十三题 奇数次中查找单独出现一次的数

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次,那么这样子分析,计算机存数假设是32位来存的,那么
可以建立一个32位的数字,来统计每一位上1出现的个数,我们知道如果某一位上为1的话,那么如果该整数出现了三次,对3去余为0,我们把每个数的对应位都加起来对3取余,最终剩下来的那个数就是单独的数字。
 
解决方法2
 
用3个整数来表示INT的各位的出现次数情况,one表示出现了1次,two表示出现了2次。当出现3次的时候该位清零。最后答案就是one的值。
- ones 代表第ith 位只出现一次的掩码变量
- twos 代表第ith 位只出现两次次的掩码变量
- threes 代表第ith 位只出现三次的掩码变量
 
解决方法3
我们把数组中数字的每一位累加起来对3取余,剩下的结果就是那个单独数组该位上的数字,由于我们累加的过程都要对3取余,那么每一位上累加的过程就是0->1->2->0,换成二进制的表示为00->01->10->00,那么我们可以写出对应关系:
 
00 (+) 1 = 01
 
01 (+) 1 = 10
 
10 (+) 1 = 00 ( mod 3)
 
那么我们用ab来表示开始的状态,对于加1操作后,得到的新状态的ab的算法如下:
 
b = b xor r & ~a;
 
a = a xor r & ~b;
 
明白了上面的分析过程,就能写出代码如下;
#include <iostream>
using namespace std;


int singleNumber1(int a[],int n)
{
    int result=0;
    for (int i = 0; i < 32; i++)
    {
        int sum=0;
        for (int j = 0; j < n; j++)
        {
            sum+=(a[j]>>i)&1;
        }
        result|=(sum%3)<<i;
    }
    return result;
}

int singleNumber2(int A[], int n)
{
    int ones = 0, twos = 0, threes = 0;
    for (int i = 0; i < n; ++i)
    {
        twos |= (ones & A[i]);
        ones ^= A[i];
        threes = ~(ones & twos);
        ones &= threes;
        twos &= threes;
    }
    return ones;
}

int singleNumber3(int A[],int n)
{
    int a = 0;
    int b = 0;
    for (int i = 0; i < n; i++)
    {
        b = (b ^ A[i]) & ~a;
        a = (a ^ A[i]) & ~b;
    }
    return b;
}

int main()
{
    int a[10]={2,2,2,4,4,4,6,7,7,7};
    int ans=singleNumber1(a,10);
    cout<<"the ans is "<<ans<<endl;

    int ans2=singleNumber2(a,10);
    cout<<"the ans is "<<ans2<<endl;

    int ans3=singleNumber3(a,10);
    cout<<"the ans3 is "<<ans3<<endl;
    return 0;
}
 
原文地址:https://www.cnblogs.com/tao-alex/p/6443069.html