算法笔记(二)出现基数次的数字

算法描述

在左程云左神的算法课上,有这样一道例题:

已知数组int[] arr :
Q1:在arr中,只有一种数出现了奇数次,其余数均出现偶数次,请找出这个出现了奇数次的数。
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恒等率,一个数异或0则等于其本身。 这样将数组里所有的数依次异或,得到的结果则是出现了基数次的那个数。

public static void PointOddTimesNumQ1Func(int[] arr){
        int eor = 0;
        for (int cur : 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的第三位不同,则这一位的异或结果为1,我们去尝试找到这一位。

        eor=a^b=11101000,则最低位=eor&(~eor+1)=00001000b,我们记作rightBit,我们可得到,a与b的二进制的第3位肯定是不相同的。

        第三步:遍历整个数组,每一个数字与rightBit进行与运算(cur&rightBit),如果得到的结果为0,则表示,有可能这个数为a/b其中的一个,但是如果是a,则表示a的二进制在第3位肯定为0,则b的第3位肯定为1。这样我们就能将a和b划分清楚界限。或者用cur&rightBit==rightBit判断,这样筛选出来的所有数,都是第3位为1的数,因为a和b是相对独立的,则非a即b。

        第四步:将第三步筛选出来的所有数进行依次异或运算。因为其他数都是偶数次出现,所以不管筛选出来其他数第三位是什么,他们自身异或的结果都是0。这样就相当于,对a或者b做了一次独立异或。异或的结果则是a或b,这样就找出了a/b。eor=a^b,我们用a/b其中的一个,去异或eor,则得到另外一个数。

注意:第三四步的核心思想,其实是怎么将a和b这两个出现了奇数次的数字进行分割。

public static void PointOddTimesNumQ2Func(int[] arr) {
        int eor = 0;
        for (int cur : arr) {
            eor^=cur;
        }
        int rightBit =0;
        rightBit = eor & (~eor+1);
        int eorAnother=0;
        for (int cur : arr) {
            if ((cur&rightBit)==rightBit)
                eorAnother^=cur;
        }
        System.out.println(eorAnother +"and"+ (eorAnother^eor));
    }

测试数组:new int[]{1,1,2,2,50,50,50,60,60,60}

以上为(cur&rightBit)==rightBit去分割a和b,测试结果为:

按照(cur&rightBit)==0条件去分割a和b,测试结果为: 

         这两个结果只是,计算出来的先后顺序不同,区别在乎你用什么样的条件,先去找出那个不同位为0的还是为1的。

补充:找两个数的不相同的最低位

        例:a^b≠0,找出a和b二进制数的不相同的最低位。
        方法为:eor=a^b,eor&(~eor+1)  

        可以看到,a和b的二进制,在第4位开始不同。

        这里本人斗胆提一句:当时在听左老师的课程时,左老师讲的是(cur&rightBit)==0和(cur&rightBit)==1是两个对立的条件,本人当时没听懂,经过Debug发现,这里左老师说错了,0应该和rightBit是对立条件,分别找出来,不同位次为1或0的数字。如果大家对这一点有疑问的话,建议自己Debug,会解答你自己的疑惑,或者评论区一起讨论。


算法真的太美了,希望大家都能坚持下去!!!!!!        

      

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值