数组中只出现一次的数字
时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
思路:
- 方法一:与前面第一个只出现一次的字符题目类似,这里采用hash-map存储
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
if(data.empty())
return ;
map<int,int>mp;
vector<int> relem;
for(int i = 0;i < data.size();i++)
{
mp[data[i]]++;
}
for(int i = 0;i < data.size();i++)
{
if(mp[data[i]] == 1)
{
relem.push_back(data[i]);
}
}
*num1= relem[0];
*num2 = relem[1];
}
};
- 方法二:利用位运算中异或的性质:两个相同数字异或为0,不同数异或为1(相同为0,不同为1)
当只有一个数出现一次时,我们把数组中所有的数,依次异或运算,最后剩下的就是落单的数,因为成对儿出现的都抵消了。
依照这个思路,我们来看两个数(我们假设是AB)出现一次的数组。我们首先还是先异或,剩下的数字肯定是A、B异或的结果,这个结果的二进制中的1,表现的是A和B的不同的位。我们就取第一个1所在的位数,假设是第3位,接着把原数组分成两组,分组标准是第3位是否为1。如此,相同的数肯定在一个组,因为相同数字所有位都相同,而不同的数,肯定不在一组。然后把这两个组按照最开始的思路,依次异或,剩余的两个结果就是这两个只出现一次的数字。
举个例子:假如该数列为:1,2,1,2,3,4
第一个数与第二个数异或:001 ^ 010 = 011
上一结果与第三个数异或:011 ^ 001 = 010
上一结果与第四个数异或:010 ^ 010 = 000
上一结果与第五个数异或:000 ^ 011 = 011
上一结果与第六个数异或:011 ^ 100 = 111
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
if(data.size() < 2)
return ;
int size = data.size();
int temp = data[0];
for(int i = 1;i < size;i++)
temp = temp ^ data[i];
if(temp == 0)
return ;
int index = 0;
while((temp & 1) == 0)
{
temp = temp>>1;
index++;
}
*num1 = *num2 = 0;
for(int i = 0;i < size;i++)
{
if(IsBit(data[i],index))
*num1 ^= data[i];
else
*num2 ^= data[i];
}
}
bool IsBit(int num,int index)
{
num = num >> index;
return (num & 1);
}
};
真的非常巧妙,值得多多研究
附上:按位与、或、异或等运算方法