一组数据中只有一个数字出现了一次。其他所有数字都是成对出现的。 请找出这个数字

首先,一个数组里面的元素可能是奇数个也可能是偶数个。同时,判断数组里的数是否成对出现有三种情况:可能有一个单数、也可能没有、还有可能有两个单数。

当数组个数奇数时:

  • 例如{1,3,5,7,1,3,5};
    数组不全成对出现,且只可能有一个单数,全部异或的结果为那个单数。

当数组个数偶数时:

  • 例如{1,3,5,1,3,5};
    数组成对出现,全部异或的结果为0。

  • 例如{3,5,7,3, 5, 11};
    数组不全成对出现,有2个单数。
    此时,每个数依次异或的结果为:0011^0101^0111^0011^0101^1011=1100。
    因为后边两位是0,则说明两个单数是从倒数三位不同的。然后让每个数右移两位 则数据会变为
    3: 0000
    5: 0001
    7: 0001
    3: 0000
    5: 0001
    11:0010
    然后把末尾为零的依次异或 在这组数据里是3 3 11; 结果得到单数11。
    把末尾为1的依次异或 在这组数据里是5 7 5;结果得到单数7。

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
void find_num(int *p, int sz)
{
    int num = 0;
    int num1 = 0;
    int num2 = 0;
    int i = 0;
    int count = 0;
    int n = 0;
    if ((sz % 2) == 1)  //数组个数为奇数
    {
        for (i = 0; i < sz; i++)
        {
            num = num ^ *(p + i);    //所有数异或结果为单数
        }
        printf("单数:%d\n", num);
    }
    else          //数组个数为偶数:一种是没有单数 还有是两个单数
    {
        for (i = 0; i < sz; i++)
            num = num^ *(p + i);
        if (num == 0)            //所有数异或结果为零说明没有单数
        {
            printf("没有单数\n");
        }
        else  //有两个单数
        {
            while (!(num & 1))
            {
                count++;
                num = num >> 1;
            }
            for (i = 0; i < sz; i++)
            {
                n = p[i] >> count; //所有数异或结果后面有几个0,
                                     //每个数依次往右移动几位
                if (n & 1) //把末位为1的数依次异或
                {
                    num1 = num1 ^ *(p + i);
                }
                else  //把末位为0的数依次异或
                {
                    num2 = num2 ^ *(p + i);
                }
            }
            printf("两个单数 :\n%d\n%d\n ", num1, num2);
        }
    }
}
void display(int *p, int sz)
{
    int i = 0;
    printf("数组为:\n");
    for (i = 0; i < sz; i++)
        printf("%d ", p[i]);
    printf("\n");
}
int main()
{
    int arr[] = { 1, 3, 5, 7, 1, 8, 3, 5 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    display(arr, sz)
    find_num(arr, sz);
    system("pause");
    return 0;
}



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值