1.数组中数字出现的次数
(1)数组中只出现一次的两个数字
数组中只有两个数只出现了一次,剩下的都出现两次,要求时间O(n),空间O(1)。
思路:任何数异或自己都等于0.先将数组进行从头到尾的异或,得到的结果是两个数字的异或值,根据这个异或值第一个为1的位的位置,把数组分为两个数组,找出这两个数。
class Solution { public: void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) { /*先考虑简化问题,如只有一个数字除外,则一次异或数组就可得到答案,本题有两个数字,因此考虑 变成两个简化问题。 在结果数字中找到第一个为1的位的位置,记为第N位。以第N位是不是1为标准把原数组中的数字分成 两个子数组,第一个子数组中每个数字的第N位都为1,而第二个子数组的每个数字的第N位都为0 。 现在我们已经把原数组分成了两个子数组,每个子数组都包含一个只出现一次的数字,而其它数字都 出现了两次。因此到此为止,所有的问题我们都已经解决。*/ int len=data.size(); if(len<2) return; int temp=data[0]; for(int i=1;i<len;i++) temp^=data[i]; int index=findFirstBitIs(temp);//找异或得到的数的第一个为1的位置 *num1=0,*num2=0; for(int i=0;i<len;i++) { if(isBit(data[i],index)==0) *num1^=data[i];//记录第N位都是0的 else *num2^=data[i];//记录第N为都是1的 } } int findFirstBitIs(int num)//找第一个为1的位的位置 { int indexBit = 0; while(((num & 1)==0) && (indexBit)<32)//如果按位与1得0,就右移一位 { num = num >> 1; ++indexBit; } return indexBit;//得到从右到左第一个为1的位置 } bool isBit(int num,int indexBit) { num = num >> indexBit; return (num & 1) == 1;//右移index位,和1与,要么相等要么不等 } };
(2)数组中唯一只出现一次的数字
在一个数组中除一个数字只出现一次之外,其他数字都出现了3次,找出这个数字。
思路:如果一个数字出现3次,那么它的二进制表示的每一位也出现三次。如果把所有出现三次的数字的二进制表示的每一位都分别加起来,那么每一位的和都能被3整除。将数组中所有数字的二进制表示的每一位都加起来,如果某一位的和能被3整除,那么那个只出现一次的数字二进制表示中对应的那一位就是0;否则就是1.
int FindNumber(int numbers[],int length) { if(numbers==nullptr||length<=0) return 0; int bitSum[32]={0}; for(int i=0;i<length;i++) { int bitMask=1; for(int j=31;j>=0;j--) { int bit=numbers[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; }