由n个元素组成的数组,n-2个数出现了偶数次,两个数出现了奇数次,且这两个数不相等,如何用O(1)的空间复杂度,找出这两个数

思路分析:

    方法一:涉及到两个数,就要用到异或定理了:若a^b=x,则a=b^x,b=x^a。对于这道题,假设这两个数分别为a、b,将数组中所有元素异或之后结果为x,因为a!=b,所以x=a^b,且x!=0,判断x中位为1的位数,只需要知道某一个位为1的位数k,如00101100,k可以取2或者3,或者5.因为x中第k位为1表示a或b中有一个数的第k位也为1,假设为a,将x与数组中第k位为1的数进行异或时,也即将x与a以及其他第k位为1的出现过偶数次的数进行异或,化简即为x与a异或,最终结果即为b。

程序示例如下:

#include "stdafx.h"
#include <stdio.h>
void FindElement(int a[], int length)
{
    if (a == NULL || length <= 0)
        printf("数组中无元素,找个毛啊。");
    else
    {
        int s = 0;
        int i;
        int k = 0;
        for (i = 0; i < length; i++)
        {
            s = s^a[i];
        }
        int s1 = s;
        int s2 = s;
        while (!(s1 & 1))
        {
            s1 = s1 >> 1;
            k++;
        }
        for (i = 0; i < length; i++)
        {
            if ((a[i] >> k) & 1)
                s = s^a[i];            
        }
        printf("%d %d\n", s, s^s2);
    }    
}
int main()
{
    int array[] = { 1, 2, 2, 3, 3, 4, 1, 5 };
    int len = sizeof(array) / sizeof(array[0]);
    FindElement(array, len);
    getchar();
    return 0;
}

    效果如图:

    方法二:如果能够把原数组分为两个子数组,在每个子数组中,包含一个只出现一次的数字,而其他数字都出现两次,问题就可以很容易的解决了:分别对两个子数组执行异或运算。

首先从头到尾依次异或数组中的每一个数字,因为其他数字都出现了两次,在疑惑中全部抵消掉了,所以最终得到的结果将是两个只出现一次的数字的异或结果。而这两个数字肯定不一样,那么这个异或结果肯定不为0,也就是说在这个结果数字的二进制表示中至少就有一位为1,否则就为0了。在结果数字中找到第一个为1的位的位置,记为第N位,那么这两个数字一个第N位为1,另一个第N位为0,这样异或后结果数字的第N位才能为1.此时以第N位是不是1为标准把原数组中的数字分为两个子数组,第一个子数组中每个数字的第N位都为1,而第二个子数组的每个数字的第N位都为0.通过这种方法就可以把原数组分成了两个子数组,每个子数组都包含一个只出现一次的数字,而其他数字都出现了两次。

代码如下:

#include "stdafx.h"
#include <stdio.h>
void findOnce(int data[], int n, int &num1, int &num2)
{
    if (n < 5)
        return;
    int r1 = 0;
    for (int i = 0; i < n; i++)
        r1 = r1^data[i];
    int bitNum = 0;
    while (!(r1 & 0x1))
    {
        r1 = r1 >> 1;
        bitNum++;
    }
    int flag = (1 << bitNum);
    num1 = 0;
    num2 = 0;
    for (int j = 0; j < n; j++)
    {
        if (data[j] & flag)
            num1 = num1^data[j];
        else
            num2 = num2^data[j];
    }
}
int main()
{
    int array[] = { 1, 2, 3, 2, 4, 3, 5, 1 };
    int num1, num2;
    findOnce(array, sizeof(array) / sizeof(array[0]), num1, num2);
    printf("%d\n%d\n", num1, num2);
    getchar();
    return 0;
}

    效果如图:

posted @ 2014-03-14 11:04  源子陌  Views(1440)  Comments(0Edit  收藏  举报