找单身狗是很经典的一道C语言编程题。顾名思义,其目的是实现在一组包含重复整型数字和单独的整型数字的数组中找到其中独有的元素
下面来看一道比较简单的单身狗例题
一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。
编写一个函数找出这两个只出现一次的数字。
例如:
有数组的元素是:1,2,3,4,5,1,2,3,4,6
只有5和6只出现1次,要找出5和6
一、整理思路
如果这个数组中只有一个是单独存在的,那么直接每个元素互相异或就可以非常快速地找出这条单身狗,但是这个数组中有两条单身狗,那么全部元素异或的方法就行不通了,但也给我们提供了一点思路。其中 异或 就是一个非常关键的切入点
接下来开始整理思路
重复元素有:1 1 2 2 3 3 4 4
单身狗有:5 6
思路一:可以用几个for循环,找到重复的元素,然后再排除掉,剩下不重复的就是单身狗
对于这个只含有10个元素的数组来说,这个方法好像确实可以,有些帅哥美女就想大不了就是多来几个for循环遍历几次就行了嘛,简单粗暴,不愧是我哈哈!!
但是,我是说万一,你遇到了一个包含成百上千个元素的数组,那么阁下又该如何应对呢
所以阁下,我知道你很急,但你先别急,听我把话讲完
既然思路一不可取,那么我们就想个思路二
开始我们说到关键点是 异或
其它重复的元素互相异或为0,那么5和6异或是什么?
把5和6转换为二进制(只需要知道关键几位就行了)
5:101
6:110
5^6:011
嘿嘿,这两个单身狗见面最会发生一些新的东西,反正不是0
阁下可能会说:嗯,然后呢
确实好像看起来没什么卵用,但你来看一下非单身狗的二进制
1:001
2:010
3:011
4:110
开始找不同和找相同:从末位开始1和3都为1,2和4都为0
5末位为1,6末位为0
在把5和6分到两个不同的组里面去
一组:5 1 1 3 3
二组:6 2 2 4 4
如果对两个组分别异或不就找到每组存在的单身狗了嘛
bingo!!思路有了,下一步架构代码
二、架构代码
1、主函数
不管三七二十一,首先写一个主函数
再创建一个函数 find_single_dog(arr,sz)
传两个参,arr数组名,其实就是传递该数组首元素的地址 sz,就是该数组含有元素的个数
int main()
{
int arr[] = { 1,2,1,2,5,3,4,3,4,6 };
int sz = sizeof(arr) / sizeof(arr[0]);
find_single_dog(arr, sz);
return 0;
}
2、自主实现find_single_dog()函数
1.先整体异或来大概找出单身狗
2.计算ret中二进制第几位为1
3.分组,最后找出单身狗
void find_single_dog(int arr[], int sz)
{
int single1 = 0;//单身狗1号
int single2 = 0;//单身狗2号
int ret = 0;
int i = 0;
//1.先整体异或来大概找出单身狗
for (i = 0;i < sz;i++)
{
ret ^= arr[i];//现在 ret = 5^6
}
//2.计算ret中二进制第几位为1
int pos = 0;
for (i = 0;i < 32;i++)
{
if (((ret >> i) & 1) == 1)
{
pos = i;//pos纪录位置,同时接受i的值,方便下面分组i的再次使用
break;
}
}
//3.分组
for (i = 0;i < sz;i++)
{
if (((arr[i] >> pos) & 1) == 0)//找到末位为0的单身狗
{
single1 ^= arr[i];//找到第一个单身狗
}
}
//假设第一组得到的单身狗为5
//ret = 5^6
//ret^single1 = 5^6^5 = 6^0 =6
single2 = ret ^ single1;
printf("%d %d\n", single1, single2);
}
搞定了