题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
示例
输入
[1,4,1,6]
返回值
[4,6]
说明
返回的结果中较小的数排在前面
解题思路
- 先使用 Set 集合存储数字,如果出现了第二个相同的数字,会在 Set 中找到对应的值,此时再将 Set 里的这个值删除。最后剩下的就是只出现过一次的数字了。我这里用的是 Java 中的 TreeSet,可以满足排序的需求。
- 对数组中所有的数进行异或运算,最终结果会得到两个不同数值的异或结果
如上面例子中的数组,做一次异或运算,最后 1 会被消去,只剩下 4 和 6 的异或结果 xor。
然后我们再找这个 xor 的最后一个 1 的位置,
因为有两个数是不重复的,所以最后一个 1 的位置说明这两个数在这个位置上的二进制,其中一个是 1,另一个是 0,我们可以根据这个特性给它们分别存放在容量为 2 的数组的不同的位置中。得到最后的 1 这个数字之后,用这个数再次与整个数组进行异或运算,重复的数会被消去,只剩下那个唯一的值。最终得出结果。
Java代码实现
- 集合存储法
import java.util.*;
public class Solution {
public int[] FindNumsAppearOnce (int[] array) {
// Lambda 表达式定义排序规则,小的在前,大的在后
TreeSet<Integer> set = new TreeSet<>((o1, o2) -> o1 - o2);
int[] res = new int[2];
for (int i = 0; i < array.length; ++i) {
if (set.contains(array[i])) { // 如果 Set 中有这个值,说明重复了
set.remove(array[i]); // 因题目只考虑 2 次,所以直接删除即可
} else {
set.add(array[i]); // 若第一次出现,加入集合中
}
}
int index = 0;
for (Integer i : set) {
res[index++] = i;
}
return res;
}
} - 位运算法
import java.util.*;
public class Solution {
public int[] FindNumsAppearOnce (int[] array) {
int xor = array[0];
for (int i = 1; i < array.length; ++i) {
xor ^= array[i];
}
// 寻找二进制中最右边的 1
xor -= xor & (xor - 1);
int[] res = new int[2];
for (int i = 0; i < array.length; ++i) {
// 根据他们是 1 还是 0,来分配在数组 res 中的位置
if ((xor & array[i]) == 0) res[0] ^= array[i];
else res[1] ^= array[i];
}
// 排序
if (res[0] > res[1]) {
int temp = res[0];
res[0] = res[1];
res[1] = temp;
}
return res;
}
} 
京公网安备 11010502036488号