异或运算(^)的运用

异或运算(^)的运用

1.概念:异或运算(^)二进制形式的数据对应位上如果相等就为0,不相等就为1

  • 0^n = n         n^n = 0

  • 异或运算满足交换律和结合律

    • a^b = b^a

    • a^b^c = a^(b^c)

  • 由异或运算的交换律和结合律可以得出:多个数据要进行异或操作最终形成一个数的值与这些数据进行异或运算的先后顺序无关

    • 实际上可以看成一种无进位相加,最终所得数据可以看进行运算的所有数据相同位上有几个1,偶数个1那么最终结果该位上就为0,反之则为1

    • 3^4^5 
      3=>0011   4=>0100   5=>0101
      1)3^4 = 0011^0100 = 0111  
      0111^5 = 0111^0101 = 0010 = 2
      2)3^5 = 0011^0101 = 0110
      0110^4 = 0110^0100 = 0010 = 2

2.例题一:在一个整型数组中有一个数出现了奇数次,其余数都出现了偶数次,找出这个出现奇数次的数

  • 解法:因为异或运算满足交换律和结合律,所以可以先把数组中的数据进行排序,相同的数放在一起,而同一个数进行异或运算的结果为0,所以出现偶数次的所有数最终结果就是0,出现奇数次的数异或运算后最后一步一定是这个数和0进行异或运算,由此就可以找出出现奇数次的这个数了

  • public class OddNum {
       public static void main(String[] args) {
           int[] arr = {2,5,8,5,8,2,3,4,6,3,4,6,5};
           int num = 0;
           for (int i = 0; i < arr.length; i++) {
               num ^= arr[i];
          }
           System.out.println(num);
      }
    }
  •  

3.例题二:一个整型数组中有两个数出现了奇数次,其余数都出现了偶数次,找出这两个出现奇数次的数

  • 步骤1:设这两个数为num1和num2,先将所有数据进行异或操作,得到的最终数据 num = num1^num2,保证num不为0

    • 因为得到的最终数据不为0,所以这两个出现奇数次的数表示为二进制的情况下,一定有某一位上对应一个1和一个0

  • 步骤2:找出两个出现奇数次的数异或运算结果 num 的最右边的那一位1

    • 做法:int rightOne = num & (~num + 1)

    • 解释1:异或运算结果最右边那一位1一定就对应了进行运算的两个数其中一个数的最右边那一位1

    • 解释2:取反(~)后,~num最右边那一位0就对应了原数据num最右边的1,取反结果加1后,新出现的0变1的那一位1就是原数据num最右边的1,此时取反加1后的结果与num进行&运算,只有0变1的这一位才会相同,所以最后就得到了num最右边的那一位1了

  • 步骤3:得到最右边的1后,就可以将原来的数组中的数据按这一位分为两组,一组是这一位为1的,一组是这一位为0的

    • 找出这组数据中该位为1的那一组数

      • 做法:遍历数组,让每个数据和rightOne进行&运算,只有该位为1的那些数的结果为0,从而将数据分成了两组

        int num1 = 0;
        for (int cur : arr) {
                   if((cur & rightOne) == 0){
                       num1 ^= cur;
                  }
              }

         

    • 做法:用num和该位为1的那组数进行异或运算,相等于变成了从一堆数据中找出出现奇数次的那个数,设为num1

  • 步骤4:此时得到了两个数的异或结果num,和其中一个数num1

    • 做法:num2 = num^num1

    • 解释:num2 = num^num1=num1^num2^num1=num2

  •  

  • public class TwoOddNum {
       public static void main(String[] args) {
           int[] arr = {1,4,5,2,6,3,6,5,4,3,2,1,4,2};
           int num = 0;
           for (int numx : arr) {
               num ^= numx;
          }
           //num = num1 ^ num2
           //num != 0
           //num必然有一个位置上是1
           int rightOne = num & (~num + 1);//提取出最右的1
           int num1 = 0;
           int num2 = 0;
           for (int cur : arr) {
               if((cur & rightOne) == 0){
                   num1 ^= cur;
              }
          }
           num2 = num ^ num1;
           System.out.println(num1 + " " + num2);

      }
    }
           
  • 如有错误,欢迎指出。

 

posted @   2022122  阅读(1274)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
· 【.NET】调用本地 Deepseek 模型
点击右上角即可分享
微信分享提示