寻找丢失的数字(一)

这是一个有趣的面试题。

有一个袋子,里面放有1, 2, 3, ... , 100, 共100个整数,且每个数字只出现一次。现在由于袋子破了个洞,造成其中一个数字丢失了。请找出丢失的数字。

很容易想到的方法是:我们可以用减法,1 + 2 + ... + 100的和减去袋子中所有数的和,其差就是丢失的那个数字。1 + 2 + ... + 100

可以由等差数列公式100 * (1 + 100) / 2 = 5050算出,我们只需要遍历一次袋子中的数字即可。

把这道题推广到一般情况:设 π 是{1, 2, ... , n}的一个全排列,π-1 是 π 中丢失了一个数字后的序列。找出序列 π-1 中缺失的数字。

当 n 比较小时,我们仍可以用上面的方法,但是当 n 很大时,上面的方法就会有溢出的问题。虽然我们可以合理安排加减法的顺序以避

免溢出,但实际上我们有更巧妙的方法来解决这类问题。

回忆异或(XOR)运算的性质:

a XOR a = 0           a XOR 0 = a

我们从1异或到100,然后再和袋子里的数逐个异或,因为一个数与自身异或,结果是0,所以异或最后的结果就是丢失的数字。

Python 代码:

def find_missing_1_number(sequence, n):
     """  returns the missing number of sequence, which is supposed to be
    a permutation of {1,..,n} with one number missing.
    
"""
    x = n
     for i  in xrange(1, n):
        x ^= i
     for e  in sequence:
        x ^= e
     return x

 

扩展问题一:如果其中两个数字丢失了,怎么办?

显然,用上述方法不能同时求出两个数。这是否意味着这种巧妙的方法不再适用了?让我们先看一下,用上述方法求出的是什么。

设丢失的两个数字为a和b,那么上述方法求出的结果就是 a XOR b。我们能否利用这个结果呢?答案是YES。因为a != b,那么

a 和 b 的二进制表示形式中一定至少有一位相异。我们可以根据该位把数字分成两组,该位为0的一组和该位为1的一组。两组分别

用上述方法异或,最后两组异或的结果就是 a 和 b。

Python 代码:

def find_missing_2_numbers(sequence, n):
     """  returns the missing two numbers of sequence, which is supposed
    to be a permutation of {1,..,n} with two numbers missing.
    
"""
    x = n
     for i  in xrange(1, n):
        x ^= i
     for e  in sequence:
        x ^= e
    diff = x & (-x)  #  isolates the rightmost 1-bit
    a, b = 0, 0
     for i  in xrange(1, n + 1):
         if i & diff:
            a ^= i
         else:
            b ^= i
     for e  in sequence:
         if e & diff:
            a ^= e
         else:
            b ^= e
     return a, b

注意在上面的方法中,我们要扫描两遍这个序列。虽然复杂度仍是O(n),但是在某些特殊情况下,我们可能没有第二次扫描的机会。

那么,能否只扫描一遍就算出结果呢?请看寻找丢失的数字(二)

 

转载于:https://www.cnblogs.com/shilcare/archive/2012/04/24/2468084.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值