题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了偶数次。请写程序找出这两个只出现一次的数字。
这题想到用map,类似于“数组中出现次数超过一半的数组”https://blog.csdn.net/Mr_xuexi/article/details/84555464
其中,data[i]是key值,出现次数count为value值。
方法一:这个方法比较容易想到,思路也比较简单。
这个就是典型的用空间换时间了,时间复杂度是O(n)。
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
if(data.size()<2)
return ;
map<int,int>m;
for(int i=0;i<data.size();i++)
m[data[i]]++;
vector<int> res;
for(int i=0;i<data.size();i++)
if(m[data[i]]==1)
res.push_back(data[i]);
*num1=res[0];
*num2=res[1];
}
};
方法二:异或法,这个方法是在讨论区看到的!(这个思路很新奇)
这个方法是,先将所有的数字一起进行异或处理,自己与自己异或是0。 那么最后的结果temp就是不相同的两个数字的异或结果。用这个结果,将数组中的数字分为两个部分。那么怎么分呢?
先判断temp中最低为1的是哪一位,两个不同的数异或,结果至少是xx1xx之类的(一定含有至少一个1,不然就全为0了)找到这个1(假设是从右往左数第三位),这说明对于这两个不同的数a和b,a的第三位是1,b的第三位是0(或者a的第三位是0,b的第三位是1,意思一样的)。
那么就可以把这个数组中的数,根据数的第三位是0或者是1分为两部分,第三位是1的是一部分,是0的为另外一部分。其中相同的数肯定会被分到同一组(相同的数肯定每一位都是相同的啊!),而a,b因为第三位不同,会被分到不同的两组中。那么这两组就分别只包含一个单独的数了,也就是分为了类似{a,xxxxxx}和{b,xxxxxx}。这样就可以对着两组分别再一次用异或的方法,相同的数异或得到0,最后异或的结果分别是a,和b。
对于异或得到不同的一个数,大家玩过扑克牌的一种玩法抽乌龟吗,这就是玩抽乌龟的那种感觉!相同的牌可以想象是被扔出去了!反正异或之后都是0!最后就只剩一个不同的数就是乌龟!
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
if(data.size()<2)
return ;
int len=data.size();
int temp=0;
int index=1;
for(int i=0;i<len;i++)
temp^=data[i]; //自己跟自己异或是0,temp是不同的那两个数字的异或结果
//找到temp中最低为1的一位(也就是两个数中相应位的数不同的一位)
while((temp&index)==0)
index<<=1;
*num1=*num2=0;
for(int i=0;i<len;i++)
{
if((data[i]&index)==0) //这里把data分为了两部分,与index有相同位为1的为一部分
*num1^=data[i]; //对这部分进行异或
else
*num2^=data[i];
}
}
};
空间复杂度是O(n),时间复杂度也比方法一要低。