本文已参与「新人创作礼」活动,一起开启掘金创作之路。 所谓单身狗问题吗,翻译成数学语言,就是在已知的一串数字,存在数字只出现一次,其余的出现两次的问题。 在这里,我用我现有的知识,为大家提供了两种解决办法。
第一种1.0:就是大家耳熟能详的将所有数字异或在一起 这种方式主要利用了按位异或的以下三点: 1.异或满足交换律
2.相同数字异或结果为0
3.0和任何数字异或都是0
通过这个方法,单独的数字便会被留下。
{
int dog = 0;
for (int i = 0; i < lenth; i++)
{
dog ^= nums[i];
}
printf("单身狗为编号:%d\n", dog);
}
但很明显,这种方法仅仅只能处理单只单身狗,但是单身狗怎么可能只有一只呢。如果有两只呢?好接下来我们来看如何处理两只单身狗。
第一种2.0(进阶)
我们知道,如果存在两只单身狗a和b,最终异或下来的结果便是a^b,再结合异或的特点:相同为0,相异为1。举个例子:
a = 5; 二进制序列:00000000000000000000000000000101;
b = 2; 二进制序列:00000000000000000000000000000010;
a^ b == 7;二进制序列:00000000000000000000000000000111;
观察上面式子,不难发现异或结果为1的地方就是两个数二进制位不同的地方,这样我们就可以通过异或结果为1的位置,对原数据进行分两类(该位置为1或0),这样每边就只有一只单身狗啦!这样再套用1.0的方法即可
{
int dogs = 0;//单身狗们(即两只单身狗异或的结果)
int offset = 0;//作为分类界限的二进制位的位置
int dog1 = 0;
int dog2 = 0;
for (int i = 0; i < lenth; i++)
{
dogs ^= nums[i];
}
for (int i = 0; i < 32; i++)
{
if ((dogs >> i) % 2 == 1)//找到两个数不同的一位
{
offset = i;
break;
}
}
for (int i = 0; i < lenth; i++)
{
if ((nums[i] >> offset) % 2 == 1)
{
dog1 ^= nums[i];
}
else
dog2 ^= nums[i];
}
printf("两只单身狗的编号分别为:%d %d\n", dog1, dog2);
}
这样就解决了两只单身狗的问题。
道德经中说过:“一生二,二生三,三生万物”(虽然没啥关系),所以单身狗也不可能只有两只,那如何处理多只呢?
接下来我提出了更泛用的方法。
第二种
利用哈希表的思想,来处理。
主要方法是通过创建一个大小为2*lenth的一维辅助数组haxmap(设待查数组长度为lenth),haxmapi用于存储待查数组中的值,haxmap[i+lenth]用于存储对应值出现的次数。 存储待查数组对应值时,这时需要有一个count变量记录已填入的待查数组中的值的个数。因此每次需要遍历比较haxmap数组前count的值中有无相同的,如果有直接在其对应位置(该位置+lenth)加1,没有便直接在haxmap[count]填入且haxmap[count+lenth]+1. 最后只需遍历后lenth个元素,找到为1的值,便打印其前lenth的对应值即可。
{
int dogs = 0;//单身狗们(即两只单身狗异或的结果)
int offset = 0;//作为分类界限的二进制位的位置
int dog1 = 0;
int dog2 = 0;
for (int i = 0; i < lenth; i++)
{
dogs ^= nums[i];
}
for (int i = 0; i < 32; i++)
{
if ((dogs >> i) % 2 == 1)//找到两个数不同的一位
{
offset = i;
break;
}
}
for (int i = 0; i < lenth; i++)
{
if ((nums[i] >> offset) % 2 == 1)
{
dog1 ^= nums[i];
}
else
dog2 ^= nums[i];
}
printf("两只单身狗的编号分别为:%d %d\n", dog1, dog2);
}
感谢观看!!!如有错误,欢迎指正!