C语言题目详解——找单身狗

目录

一.题目要求

二.思路分析

三.具体代码

四.运行截图


一.题目要求

一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。

编写一个函数找出这两个只出现一次的数字。

二.思路分析

        本题的关键第一在于这两个单身狗数和其他数的区别,第二在于这两个单身狗数之间的区别。

在解决这两个问题之前,我们先来了解一下异或运算符 ( ^ ) 。

概念:异或运算符"∧"也称XOR运算符。它的规则是若参加运算的两个二进位同号,则结果为0(假);异号则为1(真)。即 0∧0=0,0∧1=1, 1^0=1,1∧1=0。

简记:相同为0,不相同为1。

运算 说明
0 ^ 0=0,0 ^ 1=1 0异或任何数,其结果=任何数
1 ^ 0=1,1 ^ 1=0 1异或任何数,其结果=任何数取反
x ^ x=0 任何数异或自己,等于把自己置0

在C语言中( ^ )代表了按位异或,即以数字的二进制数为基础,每一位都进行异或运算。

        通过以上了解,我们能够知道异或能够将两个数之间每一位数不同置1,相同置0,那么首先我们可以利用异或的特性去遍历整个数组,设置一个初始值e(e的初值为0)依次异或数组中每个元素,最后就能得到两个单身狗数异或的结果,这也就成功的实现了第一个关键问题,即区分出来两个单身狗数和数组中其他数。但到这一步为止我们也只得到了两个单身狗数异或的结果,关于这两个数具体是哪两个数我们还需要再进行一些操作。

        第二个问题就是如何分别区分出来这两个单身狗数并表示出来,我们已经得到了两个单身狗数异或的结果,那我们就了解到了这两个数的二进制表示中哪些位是不相同的(这一位为1),那我们可以利用表达式 left = e & (~e+1) 得到e这个数二进制表达中从右往左 第一个出现1的位数(这一位为1,其余位为0)。

eg:6:110     5:101

        e = 011       left = e & (~e+1) = 001

        我们可以设置两个数 num1 = 0 和 num2 = 0 来表示这两个单身狗数,这两个数在这一位肯定是不同的(一个为1,一个为0,具体哪个为 1 哪个为 0 不清楚),那我们可以依据这一点,将整个数组分为两组,可以通过操作实现(&),其中一组是这一位为1的( (left & arr[j] ) == 1 ),另一组是这一位为0的( (left & arr[j] ) == 0 )。最后我们通过这两个条件遍历数组,就可以成功分组,由于现在每组只有一个单身狗数,我们再分别对每组中的元素进行依次异或操作,就可以分别得到一个单身狗数。

与运算 ( & (按位与)) 是计算机中一种基本的逻辑运算方式,符号表示为“&”,按二进制位进行与运算。

运算规则:0&0=0;0&1=0;1&0=0;1&1=1,即:两位同时为“1”,结果才为“1”,否则为“0”。

负数按补码形式参加按位与运算。

三.具体代码

#include<stdio.h>

void main(){
	int arr[] = { 1, 4, 6, 3, 5, 2, 1, 3, 4, 2 };
	int n = sizeof(arr) / sizeof(arr[0]);//求数组长度
	int e = 0;//0异或任何数都是那个数本身
	for (int i = 0; i < n; i++){//遍历数组 得出两个单身狗异或的结果(相同的数异或都为0)
		e ^= arr[i];
	}
	int left = e&(~e + 1);
    //记录两个单身狗最左边不相同的那一位 例如:6:110 5:101 那么left=001
	int num1 = 0, num2 = 0;//两个单身狗
	for (int j = 0; j < n; j++){
    //将数组中left位是0和1的数分为两组 一个单身狗分别在一组 分别整组异或 分别得到单身狗
		if ((left&arr[j]) == 0){//left位为0
			num1 ^= arr[j];
		}
		else{//left位为0
			num2 ^= arr[j];
		}
	}
	printf("%d %d\n", num1, num2);
}

四.运行截图

如有建议或想法 欢迎一起讨论交流~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值