异或的神奇运用——落单的数
题目:有2n+1个数,其中有n对相同的,还有一个落单的与其他都不相同,找出这个数;要求时间复杂度O(n),空间复杂度O(1)。
主流解法:将这2n+1个数全部异或起来,相同的数会抵消掉(与异或的顺序无关),最后得出的结果就是落单的数。
我的解法:一开始扫一遍过去找出数组中的中位数(题目条件可知一定存在);然后以这个数为"基准"进行快排的第一步,即完成后小于等于这个基准的数都在它左边,大于等于的都在右边。这之后呢,如果位于数组中间的不是两个相同的,那说明正中间的这个数就是落单的。如果中间是一对相同的数的话,那就看有这对数分开的左右两个数组,如果哪部分的元素个数是奇数,那么那个落单的数就一定在奇数个数的那一半里;然后再这一部分递归做与前两步相同的操作直至找出落单的数。 总的执行次数为 2(n+n/2+n/4+......n/2^k),是n乘上一个常数,故复杂度是为O(n)的;且没用到额外的数组空间,空间复杂度为O(1)。 这种抖机灵的做法思路应该是不难理解的,但实现起来的话特别是边界处理上挺麻烦的。。。 刚看到这道面试题的时候完全没想到有异或这种位运算能用,,,计算机基础知识太薄弱了。。。=_=
加强版题目:如果有2n+2个数,其中有2个数落单,该如何处理?
解法:假设两个不同的数是a和b,并且a!=b,将2n+2个数异或起来就会得到c=a xor b,并且c不等于0。因此在c的二进制位中找到一个为1的位,可推断在这位上a和b分别为0和1,因此将2n+2个数分为该位位0的组和该位为1的组,然后对这两个组分别使用上面简单版的算法就可以了。