解题思路:
在为偶数时,将所有数异或就能得到答案,因为偶数个相同数异或结果为,最终只留下了要求的数,时间复杂度,空间复杂度。
在为奇数时,若利用计数的方式来求答案,那么空间复杂度会来到,不满足题目要求。由于题目要求时间复杂度,空间复杂度。所以选择采用位运算的方式,即计算所有数在每一位的1的数目,再将该数模,最后再复原得到答案。由于int数组最多32位,所以时间复杂度是,空间复杂度是,满足要求。

1:将所有数字的二进制对应位置进行求和,用过 Excel 的胖友应该都知道求和操作,如图:
图片说明
我们假设有四个数字,其中有三个重复的 2,和一个单独的 3;

2:因为有 3 个数是重复的,所有把所有二进制位求和之后得到的数值进行取模操作,如图
图片说明
于是就得到了结果。

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param arr int一维数组 
     * @param k int 
     * @return int
     */
    public int foundOnceNumber (int[] arr, int k) {
        int[] count = new int[32];    // Java 中,int 有 32 位
        for (int i = 0; i < arr.length; ++i) {    // 将所有数的对应二进制位进行求和
            for (int j = 0; j < 32; ++j) {
                /**
                 * &同为1时为1,否则为0
                 * 假如3个2 1个3
                 * 2的二进制为
                 * 00000000000000000000000000000010
                 * & 1 相当于
                 * 00000000000000000000000000000001
                 * 第一次 bits[0] = 0 代表2的二进制的低1位是0
                 */
                count[j] += arr[i] & 1;

                /**
                 * 相当于每次无符号右移1位 高位补0
                 * 如2 >>> 1
                 * 2的二进制:
                 * 00000000000000000000000000000010
                 * >>> 1
                 * 00000000000000000000000000000001
                 * 相当于判断bits中
                 * 目的让第2次 bits[1] = 1 不停的和1做&运算 即拿2的2进制每一位 从低1位到高32位与1进行比较
                 * 同为1的时候 说明2的二进制当前位置是1 否则为0
                 */
                arr[i] >>>= 1;
            }
        }

        int res = 0;
        for (int i = 0; i < 32; ++i) {    // 求和之后再取出来,同时要取模操作
            //从高32位开始 res二进制 = 00000000000000000000000000000000
            res <<= 1;

            /**
             *
             * |同为0时为0,否则为1
             * bits存的是从低1位到高32位,所以这里要逆向
             */
            res |= count[31 - i] % k;    // 有 k 个相同的 1, 则 k % k == 0,剩下的就是多出来的那个数
        }


        return res;
    }
}