6.3:一个数组中有两种数出现了奇数次,其它数出现了偶数次,怎么找到并打印这两种数

6.3:一个数组中有两种数出现了奇数次,其它数出现了偶数次,怎么找到并打印这两种数

 

两种数出现奇数次,其它偶数次

1、用eor = 0去逐个异或,最后一定是 eor = a^b, a和b是这个两个出现奇数次的数。偶数次异或为0。

2、a != b, eor != 0;  eor的binary一定有1,利用6.2,提取最右侧的那个1的方法。

   说明a和b的二进制数在这个位置一定是不一样的。

      数组里的所有数分为2类

      第i位置是1的数

      第i位置是0的数

3、在定义eor`去异或这个数组,只挑选第i为是1的数去异或,是0的数不碰。

      eor`会把a拽出来

4、另一个 = eor^eor`

 

6      00110   

10    01010

4      00100

12    01100

3      00011

[6, 10, 6, 6, 4, 4, 12, 12, 12, 12, 3, 3]

eor异或所有后 = 6^10,偶数都为0

          6      00110   

 异或 10     01010

-------------------------------

                       01100       就拿最右边的1来观察

                       把第二位上有1的数分类

        有1的数[ 6, 4, 12 ]   无1的数[10, 3]

        用eor`去异或第二位上有1的数,成功躲掉10、3, 在6,4,12中,4和12是偶数的,eor`=6。

       另一个 = eor^eor`

 1 public static void printOddTimesNum1(int[] arr) {
 2         int eor = 0;
 3         for (int i = 0; i < arr.length; i++) {
 4             eor ^= arr[i];
 5         }
 6         System.out.println(eor);
 7     }
 8 
 9     // arr中,有两种数,出现奇数次
10     public static void printOddTimesNum2(int[] arr) {
11         int eor = 0;
12         for (int i = 0; i < arr.length; i++) {
13             eor ^= arr[i];
14         }
15         // a 和 b是两种数
16         // eor != 0
17         // eor最右侧的1,提取出来
18         // eor :     00110010110111000
19         // rightOne :00000000000001000
20         int rightOne = eor & (-eor); // 提取出最右的1
21         
22         
23         int onlyOne = 0; // eor'
24         for (int i = 0 ; i < arr.length;i++) {
25             //  arr[1] =  111100011110000
26             // rightOne=  000000000010000
27             if ((arr[i] & rightOne) != 0) {  //这个arr[i]在最右侧的位置上一定为1
28                 onlyOne ^= arr[i];
29             }
30         }
31         System.out.println(onlyOne + " " + (eor ^ onlyOne));
32     }

 

posted @ 2022-05-03 13:49  yzmarcus  阅读(140)  评论(0编辑  收藏  举报