1 题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
2 题解
2.1 哈希map
遍历一遍数组,用map记录出现的次数,然后再遍历一遍数组,找出出现1次的数字。
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
map<int ,int>mp; //定义一个map数组 存放<数值,出现次数>
int n=data.size();
for(int i=0;i<n;i++){ // 将data数组的值存入map
mp[data[i]]++;
}
vector<int> q; // 定义一个vector容器
map<int,int>::iterator it; // map数组遍历
for(it=mp.begin();it!=mp.end();it++){
if(it->second==1) // 发现只出现一次的数值
q.push_back(it->first);
}
*num1=q[0];
*num2=q[1];
}
};
2.2 位运算
前提知识:
异或运算:如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。
n^0 = n;
n^n = 0;
n^n^m = n^(n^m) 满***换律
所以,我们可以让数组中的每一个数异或一下,最后会得到一个结果res,就是两个出现一次的数字的异或结果这个结果肯定是由两个不同数字异或而来,因此我们找res二进制中为1的位置i,因为1一定是由0,1异或而来,因此要求得两个数中,一定有一个数的二进制中的第i个位置为1, 一个为0.
如何找到位置i?可用i = ret & (-ret)
因为计算机用补码存取二进制数,而负数的补码为反码+1,举个例子
假如ret = 1110 , -ret = 0010 , 所以 i = 0010
所以,再异或一遍即可得到答案。
解析:数组中所有的数进行异或得到res,假设只出现一次的数是A和B,res=A^B。找到res中第一个1出现的位置,这个位置必是AB不同出现的1,判断原数组中这个位置为1和为0的数,为1的进行异或得出一个只出现一次的数(相同的数必在一组),为0的进行异或得出一个只出现一次的数
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
int res=0;
int n=data.size();
for(int i=0;i<n;i++){
res^=data[i];
}
int q=res&(-res);
*num1=0,*num2=0;
for(int i=0;i<n;i++){
if(q&data[i])
*num1^=data[i];
else
*num2^=data[i];
}
}
};