题目一:数组中数字出现的次数
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度O(n),空间复杂度O(1)。
链接:
剑指Offer(第2版):P275
思路标签:
- 算法:问题分步解决
- 异或
解答:
- 使用异或运算的一个性质:任何一个数字异或它自己都等于0;那么如果从头到尾依次异或数组中的每个数,最终即是只出现依次的数字;
- 题中需要寻找两个只出现一次的数字,那么我们如果将原数组分成两个子数组,每个子数组中只包含一个数字,其他数字都是成对出现。
- 首先对所有元素进行异或,得到的结果是两个只出现一次的数字异或的结果,因为两个数字不一样,所以异或的结果中肯定至少有一位1;
- 我们以第一个1的位置是否出现1为划分,将数组分为两个子数组;
- 分别对每个子数组进行元素异或,则可以得到两个只出现一次的数字。
- 注意:不必进行子数组的分拆和组合,只要在第二次遍历整个数组的过程中,对每个元素进行一次属于哪个子数组的判断操作即可。
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
int length = data.size();
if(length <=0)
return;
int resultOR = 0;
for(int i=0; i<length; ++i)
resultOR^= data[i];
unsigned int indexOf1 = FindFirstBitOf1(resultOR);
*num1 = *num2 = 0;
for(int i=0; i<length; ++i){
if(IsBit1(data[i], indexOf1))
*num1 ^= data[i];
else
*num2 ^= data[i];
}
}
unsigned int FindFirstBitOf1(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);
}
};
题目二:数组中唯一只出现一次的数字
在一个数组中除一个数字只出现一次之外,其他数字都出现了三次。请找出哪个只出现一次的数字。
链接:
剑指Offer(第2版):P278
思路标签:
- 算法:位运算
解答:
- 除目标数字外其他数字都出现三次,那么其二进制表示的每一位(0或者1)也出现三次;
- 所有数字每一位均相加,每一位的和均能被3整除,不能被三整除的那一位即为目标数该位为1的情况。
class Solution {
public:
int FindNumberAppearingOnce(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;
}
};