题目描述:
给定一个长度为 的整型数组 arr和一个整数k(k>1) 。
已知 中只有 1 个数出现一次,其他的数都出现 k 次。
请返回只出现了 1 次的数。
输入:[5,4,1,1,5,1,5],3 返回值:4
目录
思路1:(暴力求解)
以每一个数去遍历整个数组,碰到相同的数就记下来,遍历完后,判断记下的数等不等于k,等于就判断下一个数,不等于就直接返回这个数。
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param arr int一维数组
* @param arrLen int arr数组长度
* @param k int
* @return int
*/
int foundOnceNumber(int* arr, int arrLen, int k) {
for (int i = 0; i < arrLen; i++) {
int count = 0;//计数器
for (int j = 0; j < arrLen; j++) {
if (arr[i] == arr[j])
count++;
}
if (count == 1)//只出现了一次的数
return arr[i];
}
return -1;
}
思路2:(位运算)
把每个数化为32位的二进制形式来运算,计算出原数组数字的相同比特位上的1的出现总次数之和,因为如果一个数出现了k次,那么他的相同比特位上就有k个1,所以用次数这和模k来判断是否出现了k次,次数模k如果等于0,说明是重复出现的数字,如果不为0,说明只出现了一次,那么把这一位的1还原再加上其他位的1还原就能得到原来的数。
比如:【1,1,2,2,3】,k=2
比特位:001,001,010,010,011
第一位上出现1的总次数是:3
第二位上出现1的总次数是:3
第一位上:3%k!=0也就是说 3不是k的倍数,说明那个没重复的数字的这一位上是1
第二位上:同上,重复的数字的这一位上也是一个1
那么利用位运算将这两个比特位上的1进行还原,然后相加就得到原来的数就是没有重复的数。
如图:
代码及详情如下:
int foundOnceNumber(int* arr, int arrLen, int k) {
//新建一个大小为32的数组,用来记录每一比特位上1出现的次数
int bit[32];
//外循环是比特位上循环
for (int i = 0; i < 32; i++) {
//相当于一个计数器
bit[i] = 0;
//内循环是数组元素循环
for (int j = 0; j < arrLen; j++) {
//先右移i位,再&1就能算出当前比特位上的数字是1还是0
bit[i] += (arr[j] >> i) & 1;
//这句可以换个法写,因为二进制上不是1就是0
//if((arr[j]>>i)&1)
// bit[i]++;
}
}
//上面记录完毕后,来遍历比特位数组
int tmp = 0;
for (int i = 0; i < 32; i++) {
//当模k不等于0时,说明不是k的倍数,就是说没有重复的那个数字的这一位上是1
if (bit[i] % k != 0)
//是比特位上第几位的1就还原几位得到十进制数,然后判断其他位
tmp += 1 << i;
}
//最后返回该数
return tmp;
}
思路3:(排序法)
把这个数组按升序排序,因为只有一个不重复的数字 ,所以其他相同数字都是相邻的,所以判断一个数字跟两边数字是否相等就能 找出没有重复的数字,分为三种情况:
- 这个数字在数组头,只需要跟后面的一个数字比较就行
- 这个数字在数组尾,只需要跟前面的一个数字比较就行
- 这个数字在数组中间,就需要跟前后两个数字都要比较了
思路4:(异或方法)
按位异或可以非常快速的查找出数组中不是重复的数字,因为相同数字异或为0,0与任何数字异或都为任何数字本身。
但是这种方法只限于当k为偶数时,也就是说重复出现次数为偶次数。
关于位运算操作符的用法: