找数组中唯一重复的元素

1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次.每个数组元素只能访问一次,设计一个算法,将它找出来;不用辅助存储空间。

(1)   方法一:(当N为比较大时警惕溢出)

将1001个元素相加减去1,2,3,……1000数列的和,得到的差即为重复的元素。

int  Find(int*   a)
	{  
		int   i;
		for  (i = 0;i<=1000;i++)    
			a[1000]   +=   a[i];    
		
		a[1000]   -=   (i*(i-1))/2;       //i的值为1001  
		
		return   a[1000];
	}

(2)   方法二:

数组取值操作可以看做一个特殊的函数f:D→R,定义域为下标值0~1000,值域为1到1000.如果对任意一个数 i,我们把f(i)叫做它的后继,i叫f(i)的前驱。0只有后继没有前驱,其他数字既有后继也有前驱,重复的那个数字有两个前驱,我们将利用这些特征。

规律:从0开始画一个箭头指向它的后继,从它的后继继续指向后继的后继,这样,必然会有一个节点指向之前已经出现过的数,即为重复的数。

 

利用下标与单元中所存储的内容之间的特殊关系,进行遍历访问单元,一旦访问过的单元赋予一个标记,利用标记作为发现重复数字的关键。

int find2(int *a) {
		int index = 0;
		while(true){
			if(a[index] < 0 ) {
				break;
			}
			a[index] = 0 - a[index];
			index = 0 - a[index];
		}
		return a[index];
	}

(3)   方法三

同样考虑下标与内容的关系,不过不用标记,而用两个速度不同的过程来访问。Slow每次前进一步,fast每次前进两步。在有环结构中,它们总会相遇。

int find3(int *a) {
		int slow =0, fast = 0;
		while( true ) {
			slow = a[slow];
			fast = a[a[fast]];
			if(slow == fast){
				break;
			}
		}
		return a[slow];
	}

(4)   方法四:异或操作

数组a[N]中的N个数异或结果与1至N-1异或的结果再做异或,得到的值即为所求。

  • 设重复数为A,其余N-2个数异或结果为B。
  • N个数异或结果为A^A^B
  • 1至N-1异或结果为A^B
  • 由于异或满足交换律和结合律,且X^X = 0 ,0^X = X;
  • 则有
  • (A^B)^(A^A^B)=A^B^B=A

int find4(int *a, int length) {
		int result = 0;
		for(int i = 1; i <= 1000; i++) {
			result ^= i;
		}
		for(int i=0; i<=1000; i++ ) {
			result ^=  a[i];
		}
		return result;
	}

摘自http://www.cnblogs.com/answeryi/archive/2012/09/24/2700529.html,部分算法有改动,其中第四个算法借鉴http://blog.youkuaiyun.com/imzoer/article/details/8013277

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值