前言
需要用最小的时空间复杂度来找出数组中出现奇数次的值;有2种场景:数组中只有一个奇数次的值; 有2个奇数次的值。 分别找出来
一、思路
利用整数的位运算, 运算满足各自规律, 如 ^ 满足交换律和结合律,
n^n = 0;
0^n = n;
二、题解
算法代码如下(示例):
public class OddNumSearch {
/**
* 要求 时 o(n) 空 o(1)
* @param arr 给定一个数组, 只有一个数出现了奇数次
* @return 找出这个奇数次的值
*/
private static int oddNumSearch01(int[] arr) {
int result = 0;
for (int i : arr) {
result = result ^ i;
}
return result;
}
/**
* 要求 时 o(n) 空 o(1)
* 一个数组中有 2个数 奇数次出现, 找出这2个数
* @param arr
* @return 2个奇数次存在的数
*/
private static int[] oddNumSearch02(int[] arr) {
int eor = 0;
// 得到了 eor = a ^ b 的结果
for (int i = 0; i < arr.length; i++) {
eor = eor ^ arr[i];
}
//位运算: ~eor 对eor的二进制位数取反
// 找出2个数不同中 最右侧位上为1的值 eor = a ^ b a和b 二进制至少有一位是1; 找出最右侧为1 代表的那个数
int rightone = eor & (~eor + 1);
int a = 0;
for (int r : arr) {
// 根据 rightone 将数组中的分成了2组, a 和 b 一定是在不同组
if((r & rightone) == 0) {
// a 代表 两个奇数之一
a = a ^ r;
}
}
// 得到 eor = a ^b 中的另一个数
int b = eor ^ a;
int[] oddNum = new int[2];
oddNum[0] = a;
oddNum[1] = b;
return oddNum;
}
//打印数组中的元素
private static void printArray(int[] arr) {
if (arr == null) {
return;
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
public static void main(String[] args) {
int [] arr = {5, 1, 2,2,1,55,55};
int num = oddNumSearch01(arr);
System.out.println(num);
int [] arr2 = {5,1,2,2,1,55,55,15};
int[] numArr = oddNumSearch02(arr2);
printArray(numArr);
}
}
总结
需要熟悉java中位运算的规则,理解其底层二进制计算的逻辑