解题思路:
在为偶数时,将所有数异或就能得到答案,因为偶数个相同数异或结果为,最终只留下了要求的数,时间复杂度,空间复杂度。
在为奇数时,若利用计数的方式来求答案,那么空间复杂度会来到,不满足题目要求。由于题目要求时间复杂度,空间复杂度。所以选择采用位运算的方式,即计算所有数在每一位的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; } }