查找一个数组中非成对的数字问题

前言:本篇文章介绍如何找出一个数组中非成对的一个数字,后边还拓展到求两个非成对的数字和三个非成对的数字中的任意一个。这几个题目主要考察的是我们对异或操作符的掌握程度。

问题一:查找数组中一个非成对的数字

  • 假设找出数组arr[]={1,1,2,2,3,3,4}中不成对出现的数字,既4.
  • 异或的性质:a^a=0;b^0=b.
  • 将数组中的所以值安位异或起来就可以找到唯一一个不成对出现的数字,既1^1^2^2^3^3^4=4

参考代码:


    #include<stdio.h>
    #include<windows.h>
    int main()
    {
        int i = 0;
        int ret = 0;
        int arr[] = { 1, 1, 2, 2, 3, 3, 4 };
        for (i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
        {
            ret ^= arr[i];
        }
        printf("ret=%d\n", ret);
        system("pause");
        return 0;
    }

问题二:查找数组中两个非成对的数字

  • 假设要找出数组arr[]={2,2,3,3,5,6}中不成对出现的两个数,既5和6
  • 如果可以把5和6分别到两组里,然后将这两组的数异或在一起,就可以得到这两个数了
  • 首先将数组的所有值异或在一起的到5和6异或的结果,既2^2^3^3^5^6=3
  • 然后找到3二进制位任意一个为1的位置,因为异或的性质是相异为1,那么如果按照这个二进制位对数组进行分组,那么5和6必然被分开了
  • 3的二进制中第一位就是1,那么我们按这位进行分组。第一位二进制位位0:{2,2,6};第一位二进制位位1:{3,3,5}
  • 最后将这两组数分别异或并输出就可以得到结果了

参考代码:


    #include<stdio.h>
    #include<windows.h>
    void find_num(int arr[], int len)
    {
        int i = 0;//循环变量
        int ret = 0;//记录数组所有值异或结果
        int pos = 0;//记录ret二进制中第一个为1的位置
        int x = 0;//记录分组后异或的结果输出
        int y = 0;//记录分组后异或的结果输出
        for (i = 0; i < len; i++)
        {
            ret ^= arr[i];
        }//数组所有值异或结果
        for (i = 0; i < 32; i++)
        {
            if (1 == ((ret >> i) & 1))
            {
                pos = i;
                break;
            }
        }//找ret二进制中第一个为1的位置
        for (i = 0; i < len; i++)
        {
            if (1==((arr[i] >> pos) & 1))
            {
                x ^= arr[i];
            }
            else
            {
                y ^= arr[i];
            }
        }//分组异或输出结果
        printf("x=%d,y=%d\n", x, y);
    }
    int main()
    {
        int arr[] = { 2, 2, 3, 3, 5, 6 };
        int sz = sizeof(arr) / sizeof(arr[0]);
        find_num(arr, sz);
        system("pause");
        return 0;
    }

问题三:查找数组中三个非成对的数字中的任意一个

  • 假设要找出数组arr[]={1,1,2,2,3,3,4,5,6}中不成对出现数字中的任意一个,既(4,5,6)中的任意一个数
  • 首先这个数组一定是奇数,如果我们按照问题二的分组办法对这个数组进行分组,分出来的两个组必然有一个奇数组,有一个是偶数组
  • 那么问题二的分组办法是否适用于这里呢?我们想想,那3个数的二进制位肯定不全相同,我们按照问题二的分法会把两个不成对的数分在一组,另一个分在一组,有一个不成对出现的那组必然是奇数个数的,那么我们只要判断哪个是奇数组并输出结果就可以了

参考代码:


    #include<stdio.h>
    #include<windows.h>
    void find_num(int arr[], int len)
    {
        int i = 0;//循环变量
        int ret = 0;//记录数组所有值异或结果
        int pos = 0;//记录ret二进制中第一个为1的位置
        int x = 0;//记录分组后异或的结果输出
        int y = 0;//记录分组后异或的结果输出
        int odd = 0;//记录分组元素的个数,判断是否为奇数
        for (i = 0; i < len; i++)
        {
            ret ^= arr[i];
        }//数组所有值异或结果
        for (i = 0; i < 32; i++)
        {
            if (1 == ((ret >> i) & 1))
            {
                pos = i;
                break;
            }
        }//找ret二进制中第一个为1的位置
        for (i = 0; i < len; i++)
        {
            if (1==((arr[i] >> pos) & 1))
            {
                x ^= arr[i];
                odd++;
            }
            else
            {
                y ^= arr[i];
            }
        }//分组异或输出结果
        if (odd & 1)//odd&1如果为奇数,返回1,如果为偶数返回0
        {
            printf("x=%d\n", x);
        }
        else
        {
            printf("y=%d\n", y);
        }
    }
    int main()
    {
        int arr[] = { 1, 1, 2, 2, 3, 3, 4, 5, 6 };
        int sz = sizeof(arr) / sizeof(arr[0]);
        find_num(arr, sz);
        system("pause");
        return 0;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值