40、数组中只出现一次的数字 再刷
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
1、常规做法
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
unordered_map<int, int> unmp;
for (int i = 0; i < data.size(); ++i) {
unmp[data[i]] += 1;
}
auto it = unmp.begin();
while (it != unmp.end()) {
if (it->second == 1) {
*num1 = it->first;
++it;
break;
}
++it;
}
while (it != unmp.end()) {
if (it->second == 1) {
*num2 = it->first;
break;
}
++it;
}
}
二刷:
1、hash表的笨方法
运行时间:3ms 占用内存:376k
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
unordered_map<int,int> unmp;
for(auto a:data){
unmp[a]++;
}
auto beg = unmp.begin();
while(beg != unmp.end())
{
if(beg->second == 1)
{
*num1 = beg->first;
beg++;
break;
}
beg++;
}
while(beg != unmp.end())
{
if(beg->second == 1)
{
*num2 = beg->first;
break;
}
beg++;
}
}
2、异或做法,很棒
当只有一个数出现一次时,我们把数组中所有的数,依次异或运算,最后剩下的就是落单的数,因为成对儿出现的都抵消了。
依照这个思路,我们来看两个数(我们假设是AB)出现一次的数组。我们首先还是先异或,剩下的数字肯定是A、B异或的结果,这个结果的二进制中的1,表现的是A和B的不同的位。我们就取第一个1所在的位数,假设是第3位,接着把原数组分成两组,分组标准是第3位是否为1。如此,相同的数肯定在一个组,因为相同数字所有位都相同,而不同的数,肯定不在一组。然后把这两个组按照最开始的思路,依次异或,剩余的两个结果就是这两个只出现一次的数字。
运行时间:3ms 占用内存:376k
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
if (data.size() < 2) return;
int totalNum = 0;
for (int i = 0; i < data.size(); i++) {
totalNum ^= data[i];//所有数异或,结果为不同的两个数字的异或
}
int sign = 0;//标志位,记录totalNum中的第一个1出现的位置
for (; sign < data.size(); sign++) {
if ((totalNum & (1 << sign)) != 0) { //左移 sign 位,将所有数字进行左移sign位,而低位补上0
break;
}
}
cout << sign << endl;
num1[0] = 0;
num2[0] = 0;
for (int i = 0; i < data.size(); i++) {
if ((data[i] & (1 << sign)) == 0) {//标志位为0的为一组,异或后必得到一个数字(这里注意==的优先级高于&,需在前面加())
num1[0] ^= data[i];
cout << "0 "<<data[i] << " " << (1<<sign) << endl;
}
else {
num2[0] ^= data[i];//标志位为1的为一组
cout << "1 " << data[i] << " " << (1 << sign) << endl;
}
}
cout << num1[0] << num2[0] << endl;
}
美女帅哥们如果觉得写的还行,有点用的话麻烦点个赞或者留个言支持一下阿秀~
如果觉得狗屁不通,直接留言开喷就完事了。