现在的位置: 首页 > 综合 > 正文

整形数组中只出现一次的数字(剑指Offer,九度OJ)

2013年02月19日 ⁄ 综合 ⁄ 共 1095字 ⁄ 字号 评论关闭

题目

题目链接:http://ac.jobdu.com/problem.php?pid=1351 ,《剑指Offer》 P211。

题目描述:一个整型数组里除了两个数字之外,其他的数字都出现了两次。

请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

解题思路

看到这个题的时候,大家通常会利用比较普通的解法,先对数组排序,然后再遍历一篇,但是题目

要求时间复杂度是O(n),空间复杂度是O(1)

此时我们只能考虑下位运算的方法了,现在思考这个问题的一个简单版本:

一个数组里除了一个数字之外,其他的数字都出现了两次。请写程序找出这个只出现一次的数字。

题目为什么要强调有一个数字出现一次,其他的出现两次?

我们想到了异或运算的性质:任何一个数字异或它自己都等于0。

有了上面简单问题的解决方案之后,我们回到原始的问题。现在考虑如何把原数组分为两个子数组。

对于这个问题,还是到 海涛大神那细看他的分析http://zhedahht.blog.163.com/blog/static/2541117420071128950682/

根据上面的解法实现自己的代码如下:

#include <stdio.h> 
#include <stdlib.h>
//p为数组集合,len 为数组长度,pn1,pn2分别为指向两个单独数的指针
void find(int *p, int len, int *pn1, int *pn2)
{
	int num = 0;
	int i;
	for(i=0; i<len; ++i)
	{
		num ^= p[i];
	}
	int offset = 1;//第一次出现1的位置,从低位开始寻找
	while(0 == (num & (1<<offset)))// 从寻低位找第一位1的位置
		offset++;
	*pn1 = 0, *pn2 = 0;
	for(i=0; i < len; i++)
		if(p[i] &(1<<offset))// 根据offset位是否为1把数组分为2个数组
			*pn1 ^= p[i];//*pn1 异或一个数组,最后得到第一单独出现的数
		else
			*pn2 ^= p[i];//同理*pn1
}


int main() 
{
	int n, num1, num2;
	int *p;

	while(EOF != scanf("%d", &n))
	{
		p = (int *)malloc(n*sizeof(int));
		for(int i=0; i<n; i++)
		{
			scanf("%d", p+i);
		}
		find(p, n, &num1, &num2);
		if(num1<num2)
			printf("%d %d\n", num1, num2);
		else
			printf("%d %d\n", num2, num1);
		free(p);
	}
	return 0;
}


抱歉!评论已关闭.