剑指offer——数组中只出现一次的数字
1、一个数字出现一次,其他数字出现两次
两个相同的数异或为0,所以将数组里的所有数依次异或,得到的结果就是只出现一次的数。
#include <iostream> using namespace std; int main() { int a[]={3,6,2,3,2,5,5}; int num=0; for(int i=0;i<7;i++) { num^=a[i]; } cout<<num<<endl; return 0; }
2、一个数字出现一次,其他数字出现N次
通过观察法,发现如果数字出现了n次,那么每一bit位之和可以被n整除。
#include <iostream> #include <string> using namespace std; int FindNumber(int a[], int n, int m) { int bits[32]; int i, j; // 累加数组中所有数字的二进制位 memset(bits, 0, 32 * sizeof(int)); for (i = 0; i < n; i++) for (j = 0; j < 32; j++) bits[j] += ((a[i] >> j) & 1); // 如果某位上的结果不能被整除,则肯定目标数字在这一位上为 int result = 0; for (j = 0; j < 32; j++) if (bits[j] % m != 0) result += (1 << j); return result; } int main() { int a[] = {2, 3, 1, 2, 3, 4, 1, 2, 3, 1}; //3代表其他数字出现3次 cout<<FindNumber(a, 10, 3)<<endl; return 0; }
3、两个数字出现一次,其他数字出现两次
和1的原理差不多,先是分别异或,得到结果,肯定不为0。找到结果1所在的位置x,将原数组分为两部分,第一部分是x为1的数的集合,第二部分是x为0的数的集合。然后分别对这两个数组异或,得到这两个出现一次的数。
#include <iostream> #include <string> using namespace std; unsigned int FindFirstBitIs1(int num) { int indexBit=0; while(((num&1)==0)&&(indexBit<8*sizeof(int))) { num=num>>1; ++indexBit; } return indexBit; } bool IsBit1(int num,unsigned int indexBit) { num=num>>indexBit; return (num&1); } void FindNumsAppearance(int data[],int length,int *num1,int *num2) { if (data==NULL||length<2) { return; } int resultExclusiveOR=0; for (int i=0;i<length;i++) { resultExclusiveOR^=data[i]; } unsigned int indexof1=FindFirstBitIs1(resultExclusiveOR); *num1=*num2=0; for (int j=0;j<length;j++) { if (IsBit1(data[j],indexof1)) { *num1^=data[j]; } else { *num2^=data[j]; } } } int main() { int a[]={4,3,6,3,2,5,5}; int temp1,temp2; FindNumsAppearance(a,7,&temp1,&temp2); cout<<temp1<<"\t"<<temp2<<endl; return 0; }
参考: