干货1-单身狗问题(异或运算符)
今天在蓝桥杯的微信公众号上看到了这样一个题目,由于题目比较有意思,我就完整的移过来了,嫌题目长可直接跳到分割线之下。
找出单身狗:
食堂规定,在窗口点餐后你会获得一个号码。但是有的时候会有情侣一起来吃饭,这个时候大妈会给这两个人相同的号码;
一天你来到食堂,因为你记得妈妈告诉你,只有名字越长的东西会带来好运,于是你开心的点了一份“超级无敌变态辣麻辣小香锅”。当你回头的时候你发现运气果然非常的棒!今天食堂的妹子好像比以前更多了,并且男女比例也比平常平衡很多。作为一个卓越的理工男,眨眨眼就发现这里有n个妹子和n+1个汉子。正当你被自己过人的数数能力折服的时候,你好像发现了有什么蹊跷......
没错!你就是那唯一的单身狗!
一瞬间你突然想把那份超长名字的超级无敌变态辣的麻辣小香锅退掉,并再也不相信妈妈的话了;
然而你看到大妈已经在准备你的菜,于是又平静了下来,这种事情你早就习惯了......
但是,大妈作为食堂的天眼通,早就洞悉了你的悲惨境遇,并检测到你的单身狗生涯还有很远要走。决定给你多加点肉,人间有真情!
但是大妈忘记了你的号码......
现在摆在大妈面前的是N个数字,这些数字中只有一个出现了一次,就是你的号码。其余的均出现了两次。那么怎么才能最快的找出哪个号码是你的呢?!!!
***************************
分割线
***************************
题目总结起来无非就是一句话:如何在一串数字中最快找到那唯一的“单身数字”(其余数字均有2个)!
作为一个老师没教过异或运算符的学生(讲没讲不知道,反正我不记得)也没学习过汇编的我:看了题目后,我的想法就是用一个数组将这串数组存储起来,然后用两个for循环嵌套,伪代码如下:
flag=0; for(i=0;i<n;i++) { for(j=i+1;j<n;j++) { if(a[i]==a[j]) {flag=1;break;} } if(!flag) {printf("%d",a[i]);break;} flag=0; }
然后我就在想,这样效率是不是太低了?随后就看了答案。
利用异或操作!异或运算的性质就是:相同为0,不同为1。因此2^2=0,3^2^2=3。所以只要将所有的数字异或起来就得到了那个单身狗的号码!
看完答案的我???什么?异或操作是什么?百度之。
用自己的话总结一下异或操作:异或操作就是二进制的半加操作,即只相加不进位。例如1001^1010=0011。当2个int型的数相同时,他们的二进制每位上的数都相同,0+0=0,1+1=0,所以两个数相同时进行异或操作结果为0。这样的话理解起来就很容易了,1^2=01^10=11=3,3^1=11^01=10=2,所以1^2^1=1^1^2=2(异或操作满足交换律:交换任意两位数结果不变)。
当交换2个变量的值的时候可以用a=a^b;b=a^b;a=a^b;
以下为自编的单身狗问题的代码(以下代码可重复使用,整数之间用空格隔开,输完一组数后按enter键):
#include<stdio.h> int main() { int x0=0,x; char a; while(scanf("%d",&x)!=EOF) { scanf("%c",&a); x0=x0^x; if(a=='\n') { printf("%d\n",x0); x0=0; } } return 0; }
以下为测试图:
如有不理解的地方欢迎交流!