1. 异或运算
1.1 定义
异或是一个数学运算,用于逻辑运算。如果 a、b 两个值不同,则异或结果为 1 ,否则结果为 0 。真值表如下:
简而言之就是,相同为0,不同为1。
异或运算满足交换律、结合律。
1.2 应用
1.2.1 swap函数
原理如下:
假设 i = 甲 ,j = 乙
ps:①任何数与0异或都为那个数;② i位置 ≠ j位置,否则会被一起洗成0,如下图。
1.2.2 出现奇偶次问题
1.2.2.1 只有一种数出现奇次
问题:对于一个数组,其中只有一种数出现了奇数次,其他所有数都出现了偶数次
要求:时间复杂度为O(N),空间复杂度为O(1)
代码如下:
// 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);
}
1.2.2.2 两种数出现奇次
问题:对于一个数组,其中有两种数出现了奇数次,其他所有数都出现了偶数次
要求:时间复杂度为O(N),空间复杂度为O(1)
代码如下:
public static void printOddTimesNum2(int[] arr) {
int eor = 0;
for(int i = 0 ; i < arr.length ; i++) {
eor ^= arr[i];
}
// a 和 b是两种数
// eor != 0
// eor最右侧的1,提取出来
// eor : 00110010110111000
// rightOne :00000000000001000
int rightOne = eor & (~eor +1 ); // 提取出最右的1
int eor1 = 0; // eor'
for(int i = 0 ; i<arr.length ; i++) {
//arr[1] = 111100011110000
//rightOne= 000000000010000
if((arr[i]& rightOne)!=0) {
eor1 ^= arr[i];
}
}
System.out.println( eor1 + " " +( eor ^ eor1 ));
}
总源程序如下:
public class EvenTimeOddTimes {
// 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);
}
public static void printOddTimesNum2(int[] arr) {
int eor = 0;
for(int i = 0 ; i < arr.length ; i++) {
eor ^= arr[i];
}
// a 和 b是两种数
// eor != 0
// eor最右侧的1,提取出来
// eor : 00110010110111000
// rightOne :00000000000001000
int rightOne = eor & (~eor +1 ); // 提取出最右的1
int eor1 = 0; // eor'
for(int i = 0 ; i<arr.length ; i++) {
//arr[1] = 111100011110000
//rightOne= 000000000010000
if((arr[i]& rightOne)!=0) {
eor1 ^= arr[i];
}
}
System.out.println( eor1 + " " +( eor ^ eor1 ));
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] arr1= {1,2,3,3,5,5,1,1,2};
printOddTimesNum1(arr1);
int[] arr2 = { 1,5,6,6,5,5,5,1,2,3,3,3 };
printOddTimesNum2(arr2);
}
}