寻找丢失的数字(一)
2012-04-24 14:56
134 查看
这是一个有趣的面试题。
有一个袋子,里面放有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),但是在某些特殊情况下,我们可能没有第二次扫描的机会。
那么,能否只扫描一遍就算出结果呢?请看寻找丢失的数字(二)。
有一个袋子,里面放有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),但是在某些特殊情况下,我们可能没有第二次扫描的机会。
那么,能否只扫描一遍就算出结果呢?请看寻找丢失的数字(二)。
相关文章推荐
- 【算法】寻找丢失的数字
- 寻找丢失的数字(二)
- 面试题之寻找丢失的数字
- 【zz】面试题之寻找丢失的数字
- MS/Google面试题:寻找丢失的数字
- 面试题之寻找丢失的数字
- 面试题之寻找丢失的数字
- [LintCode] Find the Missing Number 寻找丢失的数字
- 寻找数组中出现次数超过一半的数字
- Missing Number 丢失的数字
- 在三位整数(100至999)中寻找符合条件的整数并依次从小到大存入数组中;他既是完全平方数,又是两位数字相同,例如144,676等
- root密码丢失寻找
- php导出CSV时,超长数字精度丢失问题与前导0的字符串丢失0的问题解决
- leetcode 268. Missing Number-寻找丢失的数|位运算
- js数字位数太大导致参数精度丢失问题
- 用如下uc2gb函数分析字符串会出现数字丢失的解决办法
- php导出CSV时,超长数字精度丢失问题与前导0的字符串丢失0的问题解决
- 经典算法题:数字三角形寻找最大路径——动态规划和递归调用两种解法
- 运算 double类型的数字相加不丢失精度
- 寻找第一个丢失的正数