题目:数组A中包含n-1[0,n-1]内的不同整数,n个数中只有一个数不在所给的数组中。设计一个找到这个数的O(n)时间的算法。除了数组A自身以外,只能利用O(1)的额外空间。

与之相似的另一个题目见《算法导论》思考题4-2:问题同上,但在这里,不能由一个单一操作来访问A中的一个完整整数,因为A中整数是以二进制表示的。我们所能用的唯一操作就是“取A[i]的第j位”,这个操作所花时间为常数。题目要求:证明如果仅用此操作,仍能在O(n)时间内找出所缺整数。

第一个题目可以想出以下几种方法:

解法一:[0,n-1]这个区间中所有整数的和不变,为n*(n-1)/2,对数组A中的所有元素求和,设为s,则丢失的整数就是n*(n-1)/2 – s

解法二:异或运算。异或是个非常神奇的运算。设所缺的整数为k[0,n-1]区间中所有n个数的异或结果为s(n),异或运算满足交换率和结合率,所以s(n)可以被看作[0,n-1]中去掉k外的另外n-1个数的异或结果s(n-1)k的异或。也即:s(n)=s(n-1)^k,我们给等式两边同时异或s(n-1),等式变成了:s(n-1)^s(n)=s(n-1)^s(n-1)^k=k。而且,很明显s(n-1)其实就是数组A中所有元素的异或。所以,解法二就是:求出[0,n-1]内所有整数的异或结果s,再求出数组A中所有元素的异或结果t,所缺的整数就是s异或t

解法三:因为A自身也有n-1个位置。可以把A作为一个散列表,这样做虽然能够得到结果,但是破坏了数组A

至于《算法导论》思考题4-2的解法,在《算法艺术与信息学竞赛》上有解答。思路简述:自然数顺序的二进制表示最低位总是01交替出现,所以,首先读取数组A中所有元素的最低二进制位,如果得到的01的个数一样多,则说明所缺整数的最低二进制位为0,否则,哪个少,所缺整数的最低二进制位就是哪个。比如,我们得到所缺整数的最低二进制位为0,那么,说明数组A中最低二进制位为1的那些整数已经与此题无干,只需要在那些最低位为0的整数中找所缺整数。所以,时间复杂度是:T(n)=T(n/2)+n,计算:

n的上取整或下取整不影响时间复杂度。即T(n)=O(n)