首页 > 代码库 > 数组中两个只出现一次的数字

数组中两个只出现一次的数字

题目:

    一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字,要求:时间复杂度为O(n),空间复杂度O(1)

 

测试样例:

输入:

    8

    {2,4,3,6,3,2,5,5}

输出:

    4,6

 

解法:

    使用异或解决问题:一个数异或自己等于0,异或其他数 != 0,如果是一个数字,那么一趟遍历数组异或之后的结果就是我们要的;而现在是2个数据,那么我们需要仔细考虑怎样将两个数字分开:

    首先:将所有的数进行异或,得到一个结果不等于0的数字,因此这个结果数字在二进制位上必定最少有一位为1(因为那2个数不一样),我们从该结果的右边开始选择一个为1的位,记为第n位(这一位为1,那么就意味着第一个数的此位置上为1 ,第二个数此位置上肯定为0,或者反之,不然不可能异或 != 0);那么根据这一位的特性,将数组元素分成两个子数组,第一个子数组的每个数字的第n位为1,而第二个子数组中每个数字的第n位都是0;由于我们分组的标准是数字中的某一位是0还是1,那么出现了两次的数字肯定被分到了同一个数组;然后分别对这两部分进行再次异或得到两个数;

 

代码实现

//查找整数number最右边是1的位
int findFistBitIs1(int number)
{
    int index = 0;
    while (((index & 1) == 0) && index <= sizeof(int) * 8)
    {
        number >>= 1;
        ++ index;
    }

    return index;
}

//测试number的从右边数第indexBit位是否为1
int isBit1OnIndex(int number, int indexBit)
{
    int testNumber = 1 << indexBit;
    return (number & testNumber);
}

int main()
{
    freopen("input.txt","r",stdin);
    int n;
    cin >> n;
    int *array = new int[n];
    for (int i = 0; i < n; ++i)
    {
        cin >> array[i];
    }

    int testNumber = 0;
    for (int i = 0; i < n; ++i)
    {
        testNumber ^= array[i];
    }

    int indexOf1 = findFistBitIs1(testNumber);

    int ans1,ans2;
    ans1 = ans2 = 0;
    for (int i = 0; i < n; ++i)
    {
        if (isBit1OnIndex(array[i],indexOf1))
        {
            ans1 ^= array[i];
        }
        else
        {
            ans2 ^= array[i];
        }
    }

    cout << ans1 << " " << ans2 << endl;

    delete []array;
}


数组中两个只出现一次的数字