异或运算:相同为0,不同为1
同或运算:相同为1, 不同为0,不掌握
==上述特别不容易记住,异或运算就记成无进位相加:比如十进制6异或7,就理解为110和111按位不进位相加,得到001==
- 所以 0^N = N , N^N = 0
- 异或运算满足交换律和结合律,所以A异或B异或C = A异或(B异或C) = (A异或C)异或B
题目一:如何不用额外变量就交换两个数
a = x b = y两个数交换位置a = a ^ b # 第一步操作,此时 a = x^y , b=yb = a ^ b # 第二步操作,此时 a = x^y , b = x^y^y => b = x^0 => b = xa = a ^ b # 第三步操作,此时 a = x^y^x, b = x, a=> x^x^y => a=y//三步操作,实现交换ab的值
package class01;public class Test {public static void main(String[] args) {int a = 6;int b = 6;a = a ^ b;b = a ^ b;a = a ^ b;System.out.println(a);System.out.println(b);int[] arr = {3,1,100};System.out.println(arr[0]);System.out.println(arr[2]);swap(arr, 0, 0);System.out.println(arr[0]);System.out.println(arr[2]);}public static void swap (int[] arr, int i, int j) {// arr[0] = arr[0] ^ arr[0];arr[i] = arr[i] ^ arr[j];arr[j] = arr[i] ^ arr[j];arr[i] = arr[i] ^ arr[j];}}
==注意,如果a和b指向同一块内存,该方法不可行==
题目二:一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这种数
[2,2,1,3,2,3,2,1,1] 数组中存在四个2,两个3,三个1,定义一个常量等于0,分别对该数组中的数遍历一遍进行异或,最后,该变量等于多少,那么奇数的值就是多少。因为异或运算满足交换和结合律
Integer[] list = {3,3,4,6,7,7,4,4,6};int a1 =0 ;for (Integer integer : list) {System.out.println(integer);a1 = a1 ^ integer;}
题目三:怎么把一个int类型的数,提取出最右侧的1来
n与上(n取反加1)即可 => N & ( (~N)+1 )
题目四:一个数组中有两种不相等的数出现了奇数次,其他数出现了偶数次,怎么找到并打印这两种数
定义一个常量eor = 0,分别对该数组每个数异或,最终结果为a异或b,其中a和b就是这两个奇数,由于a!=b所以a异或b不等于0,即eor的值某一位上一定为1(有可能不止一个1随便选一个例如第八位),用该位做标记对原有数组的数进行分类,那么a和b由于第八位不相同一定被分开,再定义常量eor’ = 0分别对第八位为0的数异或,那么得到的值,就是a和b其中一个,由于之前eor = a异或b,那么在用eor和eor’异或,就是另外一个值。一般来说,随便找一个1我们就找最右侧的那个1,如题目三
package class01; public class Code07_EvenTimesOddTimes { // arr中,只有一种数,出现奇数次 public static void printOddTimesNum1(int[] arr) { int eor = 0; for (int i = 0; i < arr.length; i++) { eor ^= arr[i]; } System.out.println(eor); } // arr中,有两种数,出现奇数次 public static void printOddTimesNum2(int[] arr) { int eor = 0; for (int i = 0; i < arr.length; i++) { eor ^= arr[i]; } // eor = a ^ b // eor != 0 // eor必然有一个位置上是1 // 0110010000 // 0000010000 int rightOne = eor & (~eor + 1); // 提取出最右的1 int onlyOne = 0; // eor’ for (int i = 0 ; i < arr.length;i++) { // arr[i] = 111100011110000 // rightOne= 000000000010000 if ((arr[i] & rightOne) != 0) { onlyOne ^= arr[i]; } } System.out.println(onlyOne + “ “ + (eor ^ onlyOne)); } public static int bit1counts(int N) { int count = 0; // 011011010000 // 000000010000 1 // 011011000000 // while(N != 0) { int rightOne = N & ((~N) + 1); count++; N ^= rightOne; // N -= rightOne } return count; } public static void main(String[] args) { int a = 5; int b = 7; a = a ^ b; b = a ^ b; a = a ^ b; System.out.println(a); System.out.println(b); int[] arr1 = { 3, 3, 2, 3, 1, 1, 1, 3, 1, 1, 1 }; printOddTimesNum1(arr1); int[] arr2 = { 4, 3, 4, 2, 2, 2, 4, 1, 1, 1, 3, 3, 1, 1, 1, 4, 2, 2 }; printOddTimesNum2(arr2); } }
