出现在基数次数中如果数字出现奇数次,则其余数字出现偶数次。请找出出现奇数次的数字。Q2:arr中有两个数出现奇数次,其余数出现偶数次。请找出出现奇数次的两个数。例子:int[]{2,2,3,3,4,4,5,5,5},5出现了3次,奇数次。其余数字出现两次,出现次数为偶数次。异或运算的性质异或运算:按位运算,如果a和b的两个值不相同,则异或结果为1。如果a和b的两个值相同,则异或结果为0.符号xor表示为^。例子:a=00101011b,b=10110100b,a^b=10010001b性质:1.归零率:a^a=0;2、认同率:a^0=a;3.交换律:a^b=b^a;4.结合律:a^b^c=(a^b)^c=a^(b^c);5.自反:a^b^a=b;Q1:一种数出现异或运算的性质1,用于奇数次归零,偶数次出现的数依次混淆,结果为0。数出现奇数次的按顺序异或,结果就是数字本身。那么根据性质2常数,一个数XOR0等于它自己。这样数组中的所有数依次异或,得到的结果就是基数出现次数的数。publicstaticvoidPointOddTimesNumQ1Func(int[]arr){inteor=0;for(intcur:arr){eor^=cur;}System.out.println("基数次数为:"+eor);}Q2:两本书的次数都是奇数。假设a有奇数次,b有奇数次。首先说明a≠b,所以a^b不等于0。由此可以断定a和b的二进制数一定在某一位不同。第一步:我们先将数组中的所有元素依次异或,根据异或运算的性质,得到int[]arr=a^b的异或结果;我们记录为eor=a^b;第二步第一步:求a和b的二进制数不同的最低位例子:a=10001000b,b=0110000b,a和b的第3位不同,那么这个位的异或结果为1,我们试试找到这个位。eor=a^b=11101000,那么最低位=eor&(~eor+1)=00001000b,我们记为右位,可以得出a和b的二进制的第三位一定是不同的。第三步:遍历整个数组,对每个数和rightBit进行AND运算(cur&rightBit),如果结果为0,说明这个数有可能是a/b之一,但如果是a,则意思是a的第三位b必须为0,b的第三位必须为1。这样我们就可以明确的划分a和b。或者用cur&rightBit==rightBit来判断,这样筛选出来的所有数字都是第三位为1的数字,因为a和b是相对独立的,那么不是a就是b。第四步:对第三步筛选出的所有数字依次进行异或运算。因为其他数出现偶数次,所以不管其他数的第三位是什么,他们异或的结果都是0。这相当于对a或b做独立异或。异或的结果是a或b,所以找到a/b。eor=a^b,我们用a/b中的一个对eor进行异或,然后得到另一个数。注:第三步和第四步的核心思想其实就是如何划分出现奇数次的数a和b。publicstaticvoidPointOddTimesNumQ2Func(int[]arr){inteor=0;for(intcur:arr){eor^=cur;}intrightBit=0;rightBit=eor&(~eor+1);inteorAnother=0;for(intcur:arr){if((cur&rightBit)==rightBit)eorAnother^=cur;}System.out.println(eorAnother+"and"+(eorAnother^eor));}测试数组:newint[]{1,1,2,2,50,50,50,60,60,60}上面是(cur&rightBit)==rightBit拆分a和b,测试结果为:根据(cur&rightBit)==0条件拆分a和b,测试结果为:这两个结果只是计算的顺序不同,不同的是看你用什么条件,先找出不同的bit是0还是1.补充:求两个数的最低位不同:a^b≠0,求出a和b二进制数最低位不同。方法是eor=a^b,eor&(~eor+1),可以看出a和b的二进制数第4位不同。这里我敢提一句:听左老师课的时候,左老师讲的是(cur&rightBit)==0和(cur&rightBit)==1是两个相反的条件。左老师在这里错了。0应该是rightBit的相反条件。找出1或0不同位置的数字,如果对此有疑惑,建议大家自己调试,会解答你自己的疑惑,或者在评论区一起讨论。算法真的很美,希望大家坚持下去!!!!!!
