找出数组中只出现一次/两次/三次的数字,而其他数字都出现偶数次

原题描述:

一个数组中有一个/两个/三个数字只出现一次,其他数字都出现了偶数次。请找出一个/两个/三个只出现一次的数字?


具体实现如下:(三个出现一次的数字,有些乱,待优化)三种,均已测试通过。

#include <iostream>
#include <cstdio>
#include <cstdlib>

using namespace std;

// find the three different number in the int array where the other number is exit double
//1.找出数组中的只出现一次的一个数字
//####数组中所有数据异或后得到的值即为所求。(相同值异或为零)

//2.找出数组中的只出现一次的两个数字
//####只要能想办法将这两个数字放在两个数组中,而这两个数组由原数组分出,并且每一个数组除了这个数字外都是成对出现的(即和原数组组成相似)
//####所有数字异或后,按照所得值的二进制数中其中一位为1的位为标志,将数组分成两组,然后按1方法,找出两组中的数字。

//3.找出数组中的只出现一次的三个数字
//####这个要借助到1和2的方法,首先要想办法将三个数字分在两个数组中,而分的标准和2有些相似,也是以某一位是否为1为标志
//####但是有一种情况是,三个数的某一位全为1,这是三个数还是会分到同一数组中,没有达到将他们分在两个数组的目的,所以要找可以将他们分在两个数组的标志位。
//####我是通过判断查找的,当他们又被分到同一组时,则将找到的这个标志位置0,同时查找下一个是1的标志位,然后再分,知道找到能将他们分到不同组的标志位,
//####(这个标志位是肯定存在的,因为他们三个数字各不相同)
//####三个位异或为1的情况只有一下几种:
//  一:0 0 0 0 1 1 1 1
//  二:0 0 1 1 0 0 1 1
//  三:0 1 0 1 0 1 0 1
//异或:0 1 1 0 1 0 0 1


void FindOneNum(int array[],int length,int &num)
{
    if(length < 2)
        return ;
    for(int i = 0; i<length ;i++)
    {
        num ^= array[i];
    }
}

int FindFirstBitIs1(int num);
bool IsBitIs1(int num, int n);
void FindTwoNum(int array[],int length, int &num1,int &num2)
{
    if(length < 2)
        return ;
    int num = 0;
    for(int i = 0; i<length ;i++)
    {
        num ^= array[i];
    }
    unsigned int n = FindFirstBitIs1(num);
    num1 = num2 = 0;
    for(int j= 0; j<length; j++)
    {
        if(IsBitIs1(array[j],n))
        {
            num1 ^= array[j];
        }
        else
        {
            num2 ^= array[j];
        }
    }


}

void FindThreeNum(int array[],int length, int &num1, int &num2, int &num3)
{
    if(length < 2)
        return ;
    int num = 0;
    for(int i = 0; i<length ;i++)
    {
        num ^= array[i];
    }
    unsigned int n = FindFirstBitIs1(num);
    int n1 = 0, n2=0;
    int number1 = 0, number2 = 0;
    //申请两个数组,存放分开的元素
    int *array1 = new int[length];
    int *array2 = new int[length];

    while(n<32)
    {
        int k = 0,t=0;//实现分开的数组的计数

        for(int j= 0; j<length; j++)
        {
            if(IsBitIs1(array[j],n))
            {
                array1[k++] = array[j];
                number1 ^= array[j];
                n1++;
            }
            else
            {
                array2[t++] = array[j];
                number2 ^= array[j];
                n2++;
            }
        }
        //三个数在该位上都为1,则三个数被分到同一个组中,当三个没有被分到同一个组中的时候。
        if((number1 != 0)&&(number2 != 0))
        {
            if(n1%2==0)
            {
                FindTwoNum(array1,n1,num1,num2);
                num3 = number2;
            }
            else
            {
                FindTwoNum(array2,n2,num1,num2);
                num3 = number1;
            }

            break;
        }
        //可能三个数的这个这以为上都为1,则判断下一个异或为1的位,知道找到,三个数中所判断位只有一个的是1,另外两个的是0.
        //肯定能找到这样的一位,因为,三个数不可能完全相同。
        else
        {
            num = num ^ (1<<n);
            n = FindFirstBitIs1(num);
            continue;
        }
    }
    delete[] array1;
    delete[] array2;
}
int FindFirstBitIs1(int num)
{
    int n = 0;
    while(((num&1) == 0)&&(n < 32 ))
    {
        num = num >> 1;
        n++;
    }
    return n;
}

bool IsBitIs1(int num, int n)
{
    num = num >> n;
    return (num & 1);
}

int main()
{
    int array[]={1,1,2,2,3,3,3,5,5,6,7,7,10,8,8,9,9};
    int length = sizeof(array)/sizeof(int);
    //int num = 0;
    //FindOneNum(array,length,num);
    //printf("%d",num);

    int num1= 0 ;
    int num2 = 0;
    //FindTwoNum(array, length, num1, num2);
    //printf("%d  %d",num1,num2);

    int num3=0;
    FindThreeNum(array,length,num1,num2,num3);
    printf("%d %d %d",num1,num2,num3);
    return 0;


}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值