剑指offer 编程题(38):数组中只出现一次的数字
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2)
{
if(data.size() <= 0)
{
return;
}
map<int, int> m;
for(int i = 0;i < data.size();i++)
{
++m[data[i]];
}
for(int i = 0;i < data.size();i++)
{
if(m[data[i]] == 1)
{
*num2 = *num1;
*num1 = data[i];
}
}
}
};
分析:由于题目要求时间复杂度为O(n),所以先排序然后比较相邻数字是否相同的思路被排除。
空间复杂度是O(1),辅助空间被限制,所以hash表的思路也被排除。
那么这个题的突破口在哪里呢?注意这个数组的特殊性:其它数字都出现了两次,只有一个数出现了一次。可以想到运用异或运算,任何一个数字异或它自己都等于0。
如果我们从头到尾依次异或数组中的每一个数,那么最终的结果就是那个只出现一次的数字,因为其他出现两次的数字全部在异或中被抵消为0了(异或运算遵循交换分配率)。
举个栗子:2 3 4 2 3
所有数字依次异或运算:2 xor 3 xor 4 xor 2 xor 3 = (2 xor 2) xor (3 xor 3) xor 4= 0 xor 0 xor 4 = 4
最终结果4就是我们要找的那个只出现一次的数字。
void FindNumsAppearOnce(int data[], int length, int &num1)
{
if (length < 2)
return;
int resultExclusiveOR = 0;
for (int i = 0; i < length; ++ i)
resultExclusiveOR ^= data[i];
num1=resultExclusiveOR ;
}
如果我们能把原来问题中的数组,分成2个子数组,使得每个子数组中都只有一个唯一的元素以及很多成对的元素,那么我们就可以求出每个子数组中唯一的元素,最终就可以得到原数组中2个出现次数唯一的元素。
方法是这样的:
首先数组中所有元素依次异或,因为相同的元素异或得到0,所以最终的答案就等于那2个唯一的元素a^b的值。
因为a,b不同,所以异或得到的答案肯定是不等于0的,那么我们就找到a^b的二进制表示中第一个为1的位,假如是第k位。而a,b两个数在第k位上是不同的,一个为0,一个为1
接下来我们将第k位是1的分成一组,第k位是0的分成一组,如果2个元素相同,那么他们第k位肯定是一样的,所以肯定被分到同一组中。而a,b则被分到2组中去了。
然后我们就可以在每个分组中异或每一个元素,最终就可以得到那2个唯一的元素。
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
if(data.size()==0) return;
int flag=0;
for(int i=0;i<data.size();i++)
flag=flag ^ data[i];
int index=0;
while(((flag&1)==0)&&flag)
{
flag=flag>>1;
index++;
}
for(int i=0;i<data.size();i++)
{
if(((data[i]>>index)&1)==1)
*num1=*num1^data[i];
else
*num2=*num2^data[i];
}
return;
}
};
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
if(data.size()==0 || data.size()<2)
return;
int xor_result=data[0];
for(int i=1;i<data.size();i++){
xor_result^=data[i];
}
if( xor_result==0)
return;
int ind=0;
while(( xor_result&1)==0){
ind++;
xor_result= xor_result>>1;
}
*num1=*num2=0;
for(int i=0;i<data.size();i++){
if(isbit(data[i],ind))
*num1^=data[i];
else
*num2^=data[i];
}
}
bool isbit(int num,int index){
num=num>>index;
return (num&1);
}
};
推荐阅读
-
剑指offer 56 数组中数字出现的次数 lintcode 82. 落单的数、83. 落单的数 II、84. 落单的数 III
-
刷题--数组中只出现一次的数字
-
【剑指offer】面试题56(1):数组中只出现一次的两个数字
-
剑指offer:数组中只出现一次的两个数字(java版)
-
剑指offer 面试题56 python版+解析:数组中只出现一次的两个数字,数组中唯一只出现一次的数字
-
剑指offer第二版-56.数组中只出现一次的两个数字
-
【算法分享】剑指offer56-数组中只出现一次的两个数字
-
剑指 Offer 56 - I. 数组中只出现一次的两个数字
-
剑指56:数组中只出现一次的数字——异或——位运算
-
《剑指Offer》Java刷题 NO.40 数组中只出现一次的数字(数组、HashMap、位运算、异或)