数组中只出现一次的数字41

来源:互联网 发布:怎么联系网络运营商 编辑:程序博客网 时间:2024/06/05 18:50

题目描述:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。例如{2,4,3,6,3,2,5,5},因为只有4,6这两个数次出现一次,所以输出4和6。

解题思路:

  1. 数组里有两个数字只出现一次,其他数字都出现两次。
  2. 异或性质:任何一个数字异或它自己都等于0.
  3. 将数组拆分成两个子数组,使得每个子数组包含一个只出现一次的数字。
  4. 首先将所有数字执行异或操作,得到result。(result是两个只出现一次的数字的异或结果)
  5. 在result中找到自右边起的第一个为1的位的位置,标记为n位。
  6. 将原数组分为两个组,第一组中每个数字的第n位都是1;第二组中每个数字的第n位都是0.
  7. 由于result是这两个只出现一次的数字的异或结果,所以它俩肯定被分配到不同的子数组。而其他出现两次的数字肯定一起被分配到用一个子数组。
  8. 再分别对两个子数组求异或,便能分别找出出现一次的数字。

测试用例:

int main(){    //输入数组    int arr[8] = {2, 4, 3, 6, 3, 2, 5, 5};    //两个结果    int num1 = 0;    int num2 = 0;    //查找    FindNumAppearOnce(arr, 8, &num1, &num2);    //输出结果    std::cout << "num1: " << num1 << std::endl << "num2: " << num2;  //Output: 6, 4    return 0;}

函数实现:

//判断在number的二进制表示中从右边数起的第一位indexBit是不是1bool IsBit1(int number, unsigned int indexBit){    number = number >> indexBit;  //右移indexBit位    return (number & 1);  //如果是1,返回true} //在整数number的二进制表示中找到最右边是1的位unsigned int FindFirstBitIs1(int num){    int indexBit = 0;    while( ( (num & 1) == 0) && (indexBit < 8 * sizeof(int))){  //等于0 及 小于最高位数 时循环        num = num >> 1;        ++indexBit;    }    return indexBit;}//主函数void FindNumAppearOnce(int *data, int length, int *num1, int *num2){    if(data == NULL || length <= 2)        return;    //对所有元素执行一次异或操作,获得两个不同数字的异或结果    int resultExclusiveOR = 0;    for(auto i = 0; i < length; ++i)        resultExclusiveOR ^= data[i];    //在resultExclusiveOR中找到自右边起的第一个为1的位    unsigned int indexOf1 = FindFirstBitIs1(resultExclusiveOR);    for(auto j = 0; j < length; ++j){        if(IsBit1(data[j], indexOf1)) //如果元素自右边起的第indexOf1位是1,(抽象的)放在第一个数组即与num1再次执行异或操作            *num1 ^= data[j];        else            *num2 ^= data[j];  //如果元素自右边起的第indexOf1位是0,(抽象的)放在第二个数组即与num2再次执行异或操作    }    //最终num1和num2分别保存了只出现一次的那两个数字}
0 0
原创粉丝点击