题目描述:
一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
数据范围:数组长度2≤n≤1000,数组中每个数的大小0<val≤1000000
要求:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)提示:输出时按非降序排列。
示例1
输入:[1,4,1,6]
返回值:[4,6]
说明:返回的结果中较小的数排在前面
示例2
输入:[1,2,3,3,2,9]
返回值:[1,9]
解法一:map
思路:
1、遍历数组,找到每个元素的出现的次数,并保存在map中。
2、通过遍历map。找到出现次数是1的数字,作为结果返回。
代码:
import java.util.*;
public class Solution {
public int[] FindNumsAppearOnce (int[] array) {
Map<Integer, Integer> map = new HashMap<>();
//遍历数组,通过map来存储每个元素出现的次数
for(int i : array){
//如果当前元素在map中已经存在,则出现次数加1;反之,则放入map
if(map.containsKey(i)){
map.put(i, map.get(i) + 1);
}else{
map.put(i, 1);
}
}
//存储结果的数组
int[] ret = new int[2];
int index = 0;
for(Integer key : map.keySet()){
//如果元素出现次数是1.则存入结果数组
if(map.get(key) == 1){
ret[index++] = key;
}
}
//返回结果
return ret;
}
}
解法二:位运算
思路:
定义一个变量,遍历数组进行异或运算,得到的值为这两个元素异或的结果。接着,提取出最右边的1,再次遍历数组,找到这个数,之后进行与运算就得到另一个数。以示例1为例:
代码:
import java.util.*;
public class Solution {
public int[] FindNumsAppearOnce (int[] array) {
//异或运算:任何数和0异或的结果都是它本身。
int ret = 0;
//遍历数组,得到出现次数为1的两个数的结果
for(int i: array){
ret ^= i;
}
//求一个不为0的数的最右边的1的写法
int right = ret & (~ret + 1);
//用来找到两个数中的一个
int num1 = 0;
//再次遍历
for(int i : array){
//如果某个数在这个位上是1,相与结果才是1
if((i & right) == 0){
num1 ^= i;
}
}
int num2 = num1 ^ ret;
int[] retArray = new int[2];
retArray[0] = num1 < num2 ? num1 : num2;
retArray[1] = num1 < num2 ? num2 : num1;
//返回结果
return retArray;
}
}