题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
思路
思路1: 哈希
先遍历一遍建立hashmap,再遍历一遍找出来
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
map<int,int> m;
for (int val:data)
{
m[val]++;
}
vector<int> ii;//存储一次出现数字的位置
for (int i=0;i<data.size();i++)
{
if (m[data[i]]==1)
ii.push_back(i);
}
*num1=data[ii[0]];
*num2=data[ii[1]];
}
};
思路2: 位运算
利用异或性质:
1.n^n=0;
2.n^0=n;
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
int xor1=0;
for (int val:data)//将所有数字异或一遍,得到的结果就是数组中两个不同数字的异或结果(性质1)
xor1^=val;
//不同数字一定存在至少一位不同,我们找到这个不同位来进行分组
int pos_1=1;
while((pos_1&xor1)==0)//从右到左找到第一个不同位
pos_1<<=1;
for (int val:data)//根据第一个不同位置进行分组
{
if ((pos_1&val)==0)
*num1=(*num1)^val;
else
*num2=(*num2)^val;
}
}
};
为了更好理解根据第一个不同位置进行分组 ,举一个例子:
1 | 2 | 2 | 3 | 3 | 4 | 5 | 4 |
---|---|---|---|---|---|---|---|
0001 | 0010 | 0010 | 0011 | 0011 | 0100 | 0101 | 0100 |
异或之后的结果:xor1=0100(即1和5的异或结果)
这样右边第一个不同的位置:pos_1=0100
再将pos_1分别与原来数组的每一个数字:
其中,与1,2,3都为0,这时将他们都异或起来,得到1(因为2,3都有两个);
与4,5都为1,这时也将他们都异或起来,得到5(因为4有两个)。
这样我们就找到了这两个不同的数字。
注意点
在coding的时候,突然发现自己对运算符的优先级又差不多忘光了,比如在上面的:
while((pos_1&xor1)==0)
写的时候缺了与的括号,一直出错,后来才反应过来。
如果不加括号,由于等于==判断优先级要比按位与&优先级高,因此会先判断等于再与。
c++运算符优先级大全