解释: 特异数:在一个整型数组中仅出现一次的数。
在算法设计中常常要求找出一个长度为N的数组A中存在的“特异数”,根据算法要求,可以分为以下几类:
1、排序法:时间复杂度O(NlogN),空间复杂度O(1)
算法思想:通过快速排序实现对于原数组A的排序,然后遍历数组,判断数组中元素与其前后元素是否相同,如果相同则继续遍历,否则返回该元素。
2、位操作:时间复杂度O(N),空间复杂度O(1)
2.1 非特异性数字出现次数为偶数:时间复杂度为O(N)
偶数个相同的整型数字“亦或”后为0,而奇数个整型数字“亦或”后为本身。
算法思想:在算法设计过程中考虑使用“亦或(^)”运算。通过遍历数组A,将数组元素与前面元素的亦或结果进行亦或运算,遍历结束返回的结果即为数组中的特异数。
核心代码如下:
int result = A[0];
for(int i=1; i<N; i++)
result = result ^ A[i];
2.2 非特异性数字出现次数为奇数:时间复杂度为O(32*N)
当非特异性数字出现次数为奇数时,可以发现基本的位运算无法满足算法要求,但是可以通过统计所有元素二进制表示是对应位置出现的1的个数,对每位中1的个数求和,然后对k取余(其中k指非特异性数字出现的次数),然后将每位与0取“或(|)”运算得到最终结果。
算法思想:首先定义一个长度为32的数组B,该数组每个元素对应原数组元素二进制表示的每位中1的个数,通过两层循环实现算法:外层循环i从0~31,对应数组B中的元素,内层循环遍历数组A,统计元素对应位置i出现1的次数,然后将B[i]对k取余,作为最终结果在该位置的数字,依次处理得到最终结果。
核心代码如下:
int[] bitsNum = new int[32];
int result = 0;
for(int i=0; i<32; i++) {
for(int j=0; j<N; j++) {
bitsNum[i] += (A[j] >> i) & 1;
}
result = result | ((bitsNum[i]%3)<<i);
}