题型
我们的问题是:“给出一个整型数组,每个元素都出现 k (k>1)次,只有一个元素出现 p 次(p >= 1,p % k != 0)。找到这个单独的元素。”
详细思路
如其他人指出的,为了执行位运算操作,我们应该考虑整数在计算机中是如何表示的——通过位。首先我们考虑一位。假设我们有一个一位数字(只能为0或者1)组成的数组,我们可以计算数组中1出现的次数,每次计算的1的次数达到一个特定的值,也就是k时,计算归0并且重新开始(以防你混淆,这里的k就是题目中的k)。要记录我们计算了多少1,就需要一个计数器。假设计数器有m位,二进制表示为:xm, …, x1(从最高位到最低位)。我们至少可以推断出计数器的下面四个特性:
1、计数器有一个初始值, 一般就是0;
2、对于数组的每次输入,如果我们遇到0,计数器保持不变;
3、对于数组的每次输入,如果我们遇到1,计数器应该增加1;
4、要覆盖k次,我们需要 2^m >= k,也就是 m >= logk。
关键部分是:在我们浏览数组时如何改变计数器中的每一位(x1到xm)。注意我们可以用位运算操作。要保证第二个特性,回想一下那个位运算操作不会在另一个运算元是0时改变本身?对,就是 x = x | 0 和 x = x ^ 0。
好,我们现在有表达式 x = x | i 或者 x = x ^ i,i 就是数组中的元素。哪个更好?我们现在还不知道。所以我们先做一下实际的计算:
一开始,计数器的所有位都初始化位0,比如,xm = 0, …, x1 = 0。因为我们要选择位操作来保证在遇到0时计数器的所有位保持不变,直到我们在数组中遇到了1。遇到第一个1之后,我们得到:xm = 0, …, x1 = 1。然后我们继续下去直到遇到第二个1,这时我们就有:xm = 0, …, x2 = 1, x1 = 0。注意x1从1变为0了。对于 x1 = x1 | i,在第二次计算时,x1还会是1。所以很明显我们应该用 x1 = x1 ^ i。那 x2, …, xm 呢?关键是要找到 x2, …, xm 什么时候会变。拿 x2 做例子。如果我们遇到 1 并且需要改变 x2 的值,那我们做这个操作时 x1 一定是什么?答案是:x1 必须是1,否则我们不应该改变 x2 ,而是应该将 x1 从 0 改为 1。所以只有当 x1 和 i 都为 1 时才应该改变 x2,写成公式就是 x2 = x2 ^ (x1 & i)。类似的 xm 也只会在 xm-1, …, x1 和 i 都为 1 时改变:xm = xm ^ (xm-1 & … &a