//从高位向低位操作 int foundOnceNumber(int* arr, int arrLen, int k ) { int num = 0; for(int i = 31; i >= 0; i--) //从右移31位到右移0位 { int cnt = 0; //每趟循环就是求某个位置的1的个数,每趟开始置0 for(int j = 0; j < arrLen; j++) { cnt += (arr[j] >> i) & 1; // 先右移i位,再和1相与,即可知从高到低第(32-i)位是几 } num = num * 2 + cnt % k; //乘权加余就可以求出这个数 } return num; }
外循环是移动的位数在变化,从右移31位到右移0位,分别求从高到低第1位到第32位上的数字的和。
内循环是针对每个位置,求所有arrLen个数的这个位置上的数之和
对于其他均出现k次的数,内循环for结束后再%k都会=0,但是如果加上一个独行者
若它在某个位置是0,则cnt % k 就会=0或者=1,且刚好是这个数每个位上的值
即根据从高到低每个位上的数求出这个十进制数。
或者从低位向高位比较
int foundOnceNumber(int* arr, int arrLen, int k ) { int sum = 0; int ret = 0; for(int i = 0; i < 32; i++){ //从右移0位到右移31位 sum = 0; for(int j = 0; j < arrLen; j++){ sum += ((arr[j])>>i)&1; //计算所有数在这个位上的值之和 } ret+=((sum%k)<<i); //对于从低到高处理每个位上的数时,还原这个数需要左移i位 } return ret; }