1.题目
2.解法1(归并排序+遍历)
时间复杂度O(nlogn) + O(n),空间复杂度O(1)
//num1,num2分别为长度为1的数组。传出参数
//将num1[0],num2[0]设置为返回结果
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Solution {
public void FindNumsAppearOnce(int[] array, int num1[], int num2[]) {
// 使用的是归并排序,时间复杂度O(nlogn)
Arrays.sort(array);
int number = 0;
int count = 0;
List<Integer> list = new ArrayList<>();
// 遍历数组,时间复杂度O(n),所以总时间复杂度为O(nlogn)
for (int i = 0; i < array.length; ++i) {
if (count == 0) {
number = array[i];
}
if (array[i] == number) {
++count;
if (count == 2) {
count = 0;
}
}
// 用或的条件解决问题(最后一个数字正好只出现1次)
if (count == 1 && (i + 1 == array.length || number != array[i + 1])) {
list.add(number);
count = 0;
}
}
num1[0] = list.get(0);
num2[0] = list.get(1);
}
}
2.解法2(异或)Best
public class Solution {
public void FindNumsAppearOnce(int[] array, int num1[], int num2[]) {
// 如果数组为null,或者数组中没有2个树,就返回
int len = array.length;
if(array == null || len < 2){
return;
}
// 求所有数组数字整体的异或值(相同为0,不同为1),相同的两个数将被抵消,只留下不同两个数的异或值
int exclusizeOR = 0;
for (int i = 0; i < len; i++) {
exclusizeOR ^= array[i];
}
/**以异或结果倒数出现的第一个1的位置为准,看数组每个数字二进制的此位置是不是为1,如果是1,为一组
* 如果是0为另外一组,将数组分为两个子数组 (拆分)
* 两个相同的数字,肯定会被分到同一组,因为该位置值相同
* 两个不同的数肯定被分到不同组,因为只有该位置两个值不同,结果才会为1
* 这样的话,就可以将题目转换为一个数组中只有1个数字只出现1次,其他数字出现2次,整个数组取异或的结果
* 肯定就是这个只出现1次的数字了
*/
int moveCount = getLastIndex(exclusizeOR);
for (int i = 0; i < len; i++) {
if(isBit1(array[i], moveCount) == 1){
num1[0] ^= array[i];
}else{
num2[0] ^= array[i];
}
}
}
public int getLastIndex(int num){
/**判断异或结果中倒数出现第一个1的位置(为什么是倒数第一个,因为这样可以和1取&,而不是最高位为1的32位的二进制数)
* 思路是将异或结果向右移动,直到和1取&,结果为1,记录移动的次数,就是倒数第一个位置
*/
int moveCount = 0;
// java移位操作都是int,所以最多移动32位
while((num & 1) == 0 && moveCount < 32){
num = num >> 1;
++moveCount;
}
return moveCount;
}
// 判断数字该位置是不是为1
public int isBit1(int num, int moveCount){
num = num >> moveCount;
return num & 1;
}
public static void main(String[] args) {
Solution s = new Solution();
int[] num1 = new int[1];
int[] num2 = new int[1];
s.FindNumsAppearOnce(new int[]{2, 4, 3, 6, 3, 2, 5, 5}, num1, num2);
System.out.println(num1[0]);
System.out.println(num2[0]);
}
}
时间复杂度为O(n), 空间复杂度为O(1)