记录方法。使用位运算。
先对所有数字进行一次异或,得到两个出现一次的数字的异或值。
在异或结果中找到为1的最低一位的位置。(这个二进制数中是1的二进制位暗含了什么个意思呢?分析不难知道,二进制位是1,就表示这两个数字在这个二进制位上的数是不同的。所以,这就是我们划分两个数到不同组的依据。)
根据这一位对所有的数字进行分组。
在每个组内进行异或操作,得到两个数字。

import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param array int整型一维数组 
     * @return int整型一维数组
     */
    public int[] FindNumsAppearOnce (int[] nums) {
         //xor用来计算nums的异或和
        int xor = 0;

        // 计算异或和 并存到xor
        // e.g. [2,4,2,3,3,6] 异或和:(2^2)^(3^3)^(4^6)=2=010
        for(int num : nums) xor ^= num;

        //设置mask为1,则二进制为0001
        // mask是一个二进制数,且其中只有一位是1,其他位全是0,比如000010,
        // 表示我们用倒数第二位作为分组标准,倒数第二位是0的数字分到一组,倒数第二位是1的分到另一组
        int mask = 1;

        // & operator只有1&1时等于1 其余等于0
        // 用上面的e.g. 4和6的二进制是不同的 我们从右到左找到第一个不同的位就可以分组 4=0100 6=0110
        // 根据e.g. 010 & 001 = 000 = 0则 mask=010
        // 010 & 010 != 0 所以mask=010
        // 之后就可以用mask来将数组里的两个数分区分开

        //找到xor中第几位是1
        while((xor & mask)==0){
            mask <<= 1; //左移一位
        }

        //两个只出现一次的数字
        int a=0, b=0;

        for(int num : nums){
            //根据&是否为0区分将两个数字分区,并分别求异或和
            if((num & mask)==0) {//第一组
                a ^= num;
            } else{//第二组
                b ^= num;
            }
        }

        return new int[]{a < b?a : b, a > b ? a:b};
    }
}