您的位置:首页 > 编程语言

【C实现算法00】一个数组中除一个(两个)数只出现一次外其它数字都出现了两次,找出这个数,编程实现。

2018-05-31 01:05 495 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/Work_Hard_Zxm/article/details/80517821

问题1:一个数组中除一个数只出现一次外其它数字都出现了两次,找出这个数,编程实现。

分析:当写出数组中每个元素的二进制序列时,很明显除了要找的数Num的二进制序列外其它序列都是成对出现的。我们知道两个完全相同的二进制序列异或(^)以后是0,所以在这里首先将0赋给Num(语句:Num = 0;),然后将数组的每个元素与Num进行异或操作,最终累计后Num的值就是要找的数。代码实现如下:

int FindNum(int a[],size_t n)
{
int Num = 0;
for (size_t i = 0; i < n;++i)
{
Num^= a[i];
}

return Num;
}
问题2:一个数组中除两个数只出现一次外其它数字都出现了两次,找出这个数,编程实现。

分析:显然这个问题是上面问题的扩展或升级,所以这里通过处理将它转化成上面问题是一个很不错的思路。我们定义一个变量ret并将其初始化为0,经过下面这个循环
int ret = 0;
for (size_t i = 0; i < n;++i)
{
ret ^= a[i];
}
得到的ret实质上是要找的Num1与Num2异或的结果,因Num1与Num2是不同的两个数,所以ret的二进制序列中至少有一个位置是1,Num1与Num2的二进制序列在这个位置的特点是一个为1另一个为0。我们定义一个变量pos并将其初始化为0(这里规定二进制序列右边起第一个位置用0标记,以此类推),经过下面这个循环后
int pos = 0;
while (1)
{
if ((ret>>pos) & 1 == 1)
break;

++pos;
}
pos标记的位置是ret的二进制序列从右起第一次出现1的那个位置。其实数组中部分元素的二进制序列在pos位置是1,部分元素的二进制序列在pos位置是0。到这里你仔细想,我们把数组中二进制序列在pos位置是1放到一起后这组数据的特点正是问题一所描述的那样,即就是除了一个数字外其他数字都是成对出现的,这里所指的“一个数字”真是我们要找的其中之一;再把数组中二进制序列在pos位置是0的放到一起也是同样的。利用这个思想具体找Num1与Num2的局部代码如下:
for (size_t i = 0; i < n; ++i)
{
if ((a[i]>>pos)&1 == 1)
Ret.Num1 ^= a[i];

else
Ret.Num2 ^= a[i];
}
整个问题的代码实现如下(具体实现用了一个结构体,完全是为了函数返回时更方便整齐):

typedef struct NUM
{
int Num1;
int Num2;
};

struct NUM FindTwoNum(int a[], size_t n)
{
struct NUM Ret;
Ret.Num1 = 0;
Ret.Num2 = 0;

int ret = 0;
for (size_t i = 0; i < n;++i)
{
ret ^= a[i];
}

int pos = 0;
while (1)
{
if ((ret>>pos) & 1 == 1)
break;

++pos;
}

for (size_t i = 0; i < n; ++i)
{
if ((a[i]>>pos)&1 == 1)
Ret.Num1 ^= a[i];

else
Ret.Num2 ^= a[i];
}

return Ret;
}

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐