《算法導論》中的練習題,
n-1個元素的數組A,含有1到n之間的n-1個數,找出缺少的那個數?
要求:O(n)
解法一:
sum = n*(n+1)/2;
sum減掉A中的每個元素,剩下的就是要找的數。
解法二:
利用異或運算,x^x==0
xor = 1^2^...^n;
xor異或A中的每個元素,最後得到的就是所求。
解法三:
增加一個空位A[n-1],將A[i]移到A[ A[i] ],
题目升级:
缺失两个数,求出这两个数。
思想:
也是采用异或。
假设,缺失的数为s1和s2。则s1^s2=1^2^3.....^n^a[0]^a[1]^....a[n-3]。这个式子一目了然,无需多解释。
问题是如何通过这个式子求出s1与s2的值。只要能求出一个值,比如说s1,则s2=s1^(s1^s2)。
s1^s2的值必然不为0,则必然存在一位,s1与s2在此对应位不同。我们就可以按照此对应位是0或者1,将1-n分为两堆,将a[0]-a[n-3]分为两堆。
将该为为1的两堆数相异或就能求出缺失的一个数。
举个例子。1-7中缺失3,4。转化为二进制位:011和100。三位都不同,我们用最后一位来判别,将1-n和数组非为两堆。
则结果为:
标志位(最后一位) | 1 | 0 |
1-n | 1、3、5、7 | 2、4、6 |
a[0]-a[n-3] | 1、5、7 | 2、6 |
用标志位为1的数进行异或
1^3^5^7^1^5^7=3。这样就求出了一个缺失数。
// in case find two missing numbers, here size is 2 less than the range n void find_missing_number2 (int a[], int size, int& miss1, int& miss2) { miss1 = 0; miss2 = 0; int number=0; for (int i=0;i<size;i++) number ^= ((i+1)^a[i]); number ^= (size+1); number ^= (size+2); // now number will be miss1^miss2 // find the binary 1 in number int k = number - (number&(number-1)); for (int i=0;i<size;i++) { if ( (i+1)&k ) miss1 ^= (i+1); if ( a[i]&k ) miss1 ^= a[i]; } if ( (size+1) & k ) miss1 ^= size+1; if ( (size+2) & k ) miss1 ^= size+2; miss2 = number ^ miss1; }
類似的問題:
1、1-1000放在含有1001个元素的数组中,只有唯一的一个元素值重复,其它均只出现一次。每个数组元素只能访问一次,设计一个算法,将它找出来;
不用辅助存储空间,能否设计一个算法实现?
2、给你n个数,其中有且仅有一个数出现了奇数次,其余的数都出现了偶数次。用线性时间常数空间找出出现了奇数次的那一个数。
3、给你n个数,其中有且仅有两个数出现了奇数次,其余的数都出现了偶数次。用线性时间常数空间找出出现了奇数次的那两个数。