一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
代码
解法一
比较笨,先排序,是的相同的数字挨在一起,这样不同的数字必然和前后数字都不一致,对于数组的第一个和最后一个元素,则需要单独处理。
public static List<Integer> findSignleAppearNumber(int[] array) {
if (array == null || array.length <= 1) {
return null;
}
// 如果数组的长度是奇数,不可能出现两个只出现一次的数字
if (array.length % 2 == 1) {
return null;
}
List<Integer> result = new ArrayList<>(2);
if (array.length == 2) {
for (int i : array) {
result.add(i);
}
return result;
}
// 对数组排序,使得出现两次的数字可以挨着
Arrays.sort(array);
// 根据前面的判断条件,此时数组长度大于等于4
// 如果第一个数字和第二个数字不相等,说明第一个数字就是只出现一次的数字
if (array[0] != array[1]) {
result.add(array[0]);
}
// 为了和前后数字对比,第一个数字和最后一个数字不比较
for (int i = 1; i < array.length - 1; i++) {
// 如果一个数字和其前后两个数字都不相等,说明该数字只出现一次
if (array[i] != array[i - 1] && array[i] != array[i + 1]) {
result.add(array[i]);
}
}
// 如果遍历没有找到,说明数组的最后一个数字是要找的
if (result.size() < 2) {
result.add(array[array.length - 1]);
}
return result;
}
public static void main(String[] args) {
int[] array = {1, 2, 2, 3};
List<Integer> list = findSignleAppearNumber(array);
for (Integer i : list) {
System.out.println(i);
}
}
解法二
借助异或,任何一个数字异或它自己都等于0,只有都为0或者都为1,才为1,如果不相同则为0
public static List<Integer> findSignleAppearNumber2(int[] array) {
if (array == null || array.length <= 1) {
return null;
}
// 如果数组的长度是奇数,不可能出现两个只出现一次的数字
if (array.length % 2 == 1) {
return null;
}
List<Integer> result = new ArrayList<>(2);
if (array.length == 2) {
for (int i : array) {
result.add(i);
}
return result;
}
// 任何一个数字异或它自己都等于0,所以xor的结果是两个只出现一次的数字的异或结果
int xor = 0;
for (int i = 0; i < array.length; i++) {
xor ^= array[i];
}
// 找出这个异或结果二进制第一次位为1的位置
// 以此来将原数组切割为两个子数组,每个子数组包含一个只出现一次的数字
// 因为位为1,说明两个数字在该位上不相同,即必然一个在该位上是0,另一个是1,这是异或的规则所致
// 所以以此来划分数组,两个数字必然在不同子数组之中
int bitIndex = findFirstBitIs1(xor);
int n1 = 0;
int n2 = 0;
for (int i = 0; i < array.length; i++) {
if (is1OfBitIndex(array[i], bitIndex)) {
n1 ^= array[i];
} else {
n2 ^= array[i];
}
}
result.add(n1);
result.add(n2);
return result;
}
/**
* 找出数字的二进制上位为1的第一次出现位置
* @param n
* @return
*/
private static int findFirstBitIs1(int n) {
int bitIndex = 0;
while ((n & 1) == 0) {
// 如果当前位不是1,则右移一位
n = n >> 1;
bitIndex++;
}
return bitIndex;
}
/**
* 判断当前数字的第index位是否是1
* @param n
* @param index
* @return
*/
private static boolean is1OfBitIndex(int n, int index) {
n = n >> index;
return (n & 1) == 0;
}