(C语言)找单身狗

#define _CRT_SECURE_NO_WARNINGS
#include<string.h>
#include <stdio.h>
#include<assert.h>
int main()
{
    //一组数和0不断异或,最后得出的数就是唯一单着的;
    //因为异或符合结合律和交换律;
    //异或(^):二进制位相同为0,不同为1;所以两个完全相同的数异或结果一定为0;


    //只有一个单身狗的情况;
    /*int dog1 = 0;
    int arr1[] = {1,5,6,5,2,7,7,6,1};
    int sz1 = sizeof(arr1) / sizeof(arr1[0]);
    for (int i=0;i<sz1;i++)
    {
        dog1 = dog1 ^ arr1[i];

    }
    printf("%d\n",dog1);*/



    //两个单身狗的情况
    //此处使用按位操作符较为合适,效率和可读性都比较高;
    int ret = 0;
    int arr[] = {1,5,6,5,2,7,6,7,1,3};//可以看到,单身狗数为2,3;
    int sz = sizeof(arr) / sizeof(arr[0]);
    for (int i = 0; i < sz; i++)
    {
        ret = ret ^ arr[i];//两个单身狗数按位异或的结果;

    }
    
    
    int count = 0;//标记变量;
    for (int i=0;i<32;i++)
    {

        
        //按位异或:相同为0,不同为1;
        //按位与:都为1结果才为1,否则为0;
        //按位或:都为0结果才为0,否则为1;

        //遍历ret(两个单身狗数按位异或的结果),第一次出现的1,则意味着两个数在此位不同;
        //1的二进制补码:  00000000 00000000 00000000 00000001
        if ( (  (ret>>i)&1 )==1 )//按位右移(针对二进制位),去除最后一位,左边补0;
        {

    //此处按位异或后的结果应该是 2^3==001;
            //任何数和1按位与,前31位都为0,最后一位如果是1,那么结果等于1,否则结果为0;
            //任何数和0按位与,结果都为 00000000 00000000 00000000 00000000;
            
            //任何数和0按位或,结果都为它本身;
            //任何数和0按位异或,结果也都为它本身;
            count = i;//count意思是第几个二进制位不相同,此处count为0,跳出循环;
            break;
        }

    }
    //分组按位异或,把第count位相同的数分为一组;
    
    int dog1 = 0;
    int dog2 = 0;
//让两组数都从0开始异或,防止出现一个单身狗刚好单独在一组的情况;
    for (int i=0;i<sz;i++)
    {
        if ( ( (arr[i]>>count) &1) ==1 )
//右移count(0)位后,最后一位为1的所有数开始按位异或;
        {
                //所以dog1应该为3;
            dog1 = dog1 ^ arr[i];
        }
       else
        {
              dog2=dog2^arr[i];
         }


    }
    //dog2 = ret ^ dog1;//此处相当于2^3^3,结果自然等于2;

    printf("%d %d",dog1,dog2);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值