找出1到N中缺少的數?

《算法導論》中的練習題,

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个数,其中有且仅有两个数出现了奇数次,其余的数都出现了偶数次。用线性时间常数空间找出出现了奇数次的那两个数。

posted on 2013-02-25 22:31  mhgu  阅读(1364)  评论(0编辑  收藏  举报