您的位置:首页 > 其它

在一个数组中找出只出现一次的一个数字、两个数字,而其余数字全部成对出现。

2017-04-23 12:14 281 查看

经典题目:

1.在一个数组中找出只出现一次的一个数字,其余数字全部成对出现。

2.在一个数组中找出只出现一次的两个数字,其余数字全部成对出现。

那么,接下来,我们分别对这两个问题进行探讨以及代码实现。

问题1:

       若一个数组中一个数字只出现了一次,其余数字全部成对出现,那么要找出这个出现了一次的数字,办法很简单,对这个数组中的数字进行异或运算就好了,根据异或的性质“相同为0,相异为1”,即可找出该数字。

       So,具体算法我们已经知道了,那么,如何用代码实现呢?

代码如下:#include <stdio.h>
#include <stdlib.h>
int find_num(int arr[], int sz)
{
int i = 0;
int ret = 0;
for (i = 0; i<sz; i++)
{
ret ^= arr[i];
}
return ret;
}

void test1()
{
int arr[] = { 1, 3, 5, 1, 3, 5, 4 };
int sz = sizeof(arr) / sizeof(arr[0]);
int ret = find_num(arr, sz);
printf("%d\n", ret);
}

int main()
{
test1();
return 0;
}运行结果:



      这样,代码就实现了。

问题2:

        若一个数组中只有两个数字是出现一次,其他数字全部都出现了两次,那么,要找出这两个出现了一次的数组,应该用什么办法呢?
        思考一下......

        首先,从头到尾依次异或数组中的每一个数字,最终得到的结果就是两个只出现一次的数字的异或结果。因为其他数字都出现了两次,在异或中全部抵消掉了,由于这两个数字肯定不一样,那么异或的结果肯定不为0,也就是说在这个结果数字的二进制表示中至少就有一位为1。

        我们在结果数字中找到第一个为1的位的位置,记为第N位。现在我们以第N位是不是1为标准把原数组中的数字分成两个子数组,第一个子数组中每个数字的第N位都为1,而第二个子数组的每个数字的第N位都为0。

        最终,我们对这两个子数组中的元素分别进行异或运算,就可以得到该数组中只出现一次的两个数了。

        So,具体算法我们已经知道了,那么,我们又该如何用代码实现呢?

代码如下:
#include <stdio.h>
#include <stdlib.h>

int find_num(int arr[],int sz)
{
int i = 0;
int ret = 0;
int num1 = 0;
int num2 = 0;
int flag = 0; //设置标志位,即1先出现的位置
for (i = 0; i < sz; i++) //首先,异或数组中的所有元素
{
ret ^= arr[i];
}
for (i = 0; i < 32; i++) //然后,找异或后该数字二进制最先出现1的位置
{
if (((ret >> i) & 1) != 1) //找异或后该数字二进制最先出现1的位置
{
flag++;
}
else
break;
}
for (i = 0; i < sz; i++) //最后,将数组分成两个子数组,分别异或得到出现一次的数
{
if (((arr[i] >> flag) & 1) == 1)
{
num1 ^= arr[i];
}
else
num2 ^= arr[i];
}
printf("%d %d\n", num1, num2);
}

void test2()
{
int arr[] = { 1, 1, 2, 2, 3, 4, 5, 5 };
int sz = sizeof(arr) / sizeof(arr[0]);
int ret = find_num(arr,sz);
}

int main()
{
test2();
return 0;
}
运行结果:



       这样,找这两个出现一次的数字就实现了。 

总结一下:

       其实,这两道经典的题目的本质就是掌握异或运算的实质,在此基础上,将问题应用化、简单化,最终对问题进行代码的实现。 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐