700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 异或运算练习:找出一组数中唯一(唯二)出现奇数次的数

异或运算练习:找出一组数中唯一(唯二)出现奇数次的数

时间:2019-07-29 00:55:13

相关推荐

异或运算练习:找出一组数中唯一(唯二)出现奇数次的数

题目描述

已知一个数组,现在请你用时间复杂度O(n),空间复杂度O(1)的算法求解:

1.假设数组中只有一个数的数量为奇数,其余都是偶数,请求出这个数。

2.假设数组中有两个数的数量为奇数,其余都是偶数,请求出这两个数。

问题一解法

问题一比较容易,只有一个数的数量为奇数,那么,设定一个变量,然后依次异或整个数组,最后剩下的数就是那个奇数。

原理分析:因为异或运算中,同一个数和自己本身异或的结果为0,0和任何数异或的结果不变,因此,所有偶数的异或结果为0,然后0和奇数个数的那个数异或的结果不变,因此,最后剩下的就是那个奇数。

代码

public static int getOnlyJiShu(int[] arr){int res=0;for (int i = 0; i < arr.length; i++) {res=res^arr[i];}return res;}

问题二解法

1.首先,参考 问题一的思路,我们还是把数组中所有的数异或一遍,结果为那两个奇数异或。例如,数组中a和b的数量为奇数,那么,把整个数组异或一遍后,结果为a^b

2.拿到了a^b的结果,我们如何将ab分开呢?这里,可以想象,既然题目给了两个数,那么,ab就不可能相等,对吧?两个不相等的数,异或的结果,肯定至少有某一位二进制不为0。为什么?因为异或运算就是相同为0,不同为1,如果ab异或的结果为0,说明ab每一位都相等,对吧?那a就等于b,显然,题目条件给的是ab不等,因此,ab异或的结果,肯定不为0,也就是说,肯定某一个二进制位不为0。

3.从第二步推理可以看出,a^b的结果不为0,那么,我们可以任意找一位1,1说明在这一位上,ab是不相同的。然后,再设定一个变量,根据这一位是0还是1,其实都可以,然后再次异或遍历整个数组,结果就是ab中的一个。

这一步怎么理解?可以理解为,根据ab异或为1的那一位,将ab在原来的数组中分到两个区间内,然后,在原来的数组中的一个区间内再次用异或运算遍历,就能得到ab中的一个数。至于两个区间分开后,其他偶数肯定也分开到两个区间了,并且相同的偶数肯定在同一个区间,因此,偶数异或的结果仍然全部是0。

4.最后,只需要用a^b的结果,再次异或ab中的一个,另一个也就求出来了。

代码

public static void getTwoJiShu(int[] arr){int res=0;for (int i = 0; i < arr.length; i++) {res=res^arr[i];}//获取最右边的1int rightOne=res&(~res+1);int resOne=0;for (int i = 0; i < arr.length; i++) {if((arr[i]&rightOne)==0){resOne=resOne^arr[i];}}System.out.println(resOne+" "+(resOne^res));}

代码中,如何获取最右边的第一位1的代码比较经典:

int rightOne=res&(~res+1);

~res是取反操作,二进制0变1,1变0

取反后加1,其实就是补码。

补码和原数相与的结果,就是原数右边第一位为1的数,其余都是0

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。