剑指Offer对答如流系列 - 数组中数字出现的次数
Posted jefferychenxiao
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指Offer对答如流系列 - 数组中数字出现的次数相关的知识,希望对你有一定的参考价值。
面试题56:数组中数字出现的次数
题目描述
问题(1)数组中只出现一次的两个数字
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
问题(2)数组中唯一只出现一次的数字
在一个数组中除了一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
问题分析
问题(1)分析
在这篇文章剑指Offer对答如流系列 - 二进制中 1 的个数中,我们详细探讨了位运算,其中有重要的一条:两个相同的数异或的结果是 0,一个数和 0 异或的结果是它本身
如果数组中只有一个数字只出现一次,我们从头到尾异或每个数字,那么最终的结果刚好是那个只出现一次的数字。
本题里数组中有两个数字只出现一次,所以要做一些处理:
我们依旧从头到尾异或每个数字,最终的结果就是这两个只出现一次的数字的异或结果,由于两个数不同,结果数字中一定有一位为1,把结果中第一个为1的位置记为第n位。由于是两个只出现一次的数字的异或结果,因此这两个数字在第n位上的数字一定是1和0。
接下来根据数组中每个数字的第n位上的数字是否为1来进行分组,恰好能将数组分为两个都只有一个数字只出现一次的数组,对两个数组从头到尾异或,就可以得到这两个数了。
问题(2)分析
数字出现了三次,不能直接利用异或位运算进行消除相同个数字。但是仍然可以沿用位运算的思路。
将所有数字的二进制表示的对应位都加起来,如果某一位能被三整除,那么只出现一次的数字在该位为0;反之,为1。
问题解答
问题(1)
public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) {
if(array==null || array.length<2) {
return;
}
int resultExclusiveOR=0;
for(int i=0;i<array.length;i++) {
resultExclusiveOR^=array[i];
}
int indexOf1=0;
while(((resultExclusiveOR&1) == 0) && (indexOf1 <= 32)){
//易错点:只有n>>1不完整,要n=n>>1
resultExclusiveOR = resultExclusiveOR>>1;
indexOf1++;
}
num1[0]=0;
num2[0]=0;
for(int i=0;i<array.length;i++){
if(((array[i]>>indexOf1)&1) == 1) {
num1[0]^=array[i];
} else {
num2[0]^=array[i];
}
}
}
问题(2)
public int findNumberAppearingOnce(int[] arr) {
if(arr==null || arr.length<=0) {
throw new RuntimeException();
}
int[] bitSum = new int[32];
Arrays.fill(bitSum, 0);
for(int i=0;i<arr.length;i++) {
int bitMask=1;
for(int j=31; j>=0; j--) {
int bit= arr[i]&bitMask;
if(bit!=0) {
bitSum[j]+=1;
}
bitMask=bitMask<<1;
}
}
int result=0;
for(int i=0;i<32;i++) {
result=result<<1;
result+=(bitSum[i]%3);
}
return result;
}
以上是关于剑指Offer对答如流系列 - 数组中数字出现的次数的主要内容,如果未能解决你的问题,请参考以下文章