给定一个只包含整数的有序数组,每个元素都会出现两次,唯有一个数只会出现一次,找出这个数。
示例 1:
输入: [1,1,2,3,3,4,4,8,8]
输出: 2
示例 2:
输入: [3,3,7,7,10,11,11]
输出: 10
class Solution {
public:
int singleNonDuplicate(vector<int>& nums)
{
int tmp=0;
for(int i =0;i<nums.size();i++)
{
tmp^=nums[i];//异或
}
return tmp;
}
};
//0^x=x; a^a=0;
//规则x^a^b^c^x=a^b^c
因此逐个异或相同的数字都抵消 为零,就只剩下一个单一的数字
扩展:
找出数组中的两个单一元素,其他元素都是出现两次的
思路:按照上面的方法,把所有数字异或,得到的结果就是那两个不同的数字异或后的结果
现在,我们要把数组分成两个部分,要求是:这个个不同的数字在不同部分,而且相
同的数字在同一部分这样我们就把问题转变位于与上面问题相同的问题了,也就是在
数组中找唯一一个单一元素。
那末到底应该怎摸去分呢,这两个数异或的结果肯定不为0(为零说明相等),那末我
们就可以在他异或的结果中找到第n位(这个n可以随便定位,只要满足第n位为1即可,为
了方便我们找从右往左第一个为1的位置)为1的数,然后将数组中所有的数都以这个标准
划分,第n位为零的放一边,第n位为1的放一边,这样就划分出来的肯定是满足上面要求的
void FindNumsAppearOnce(int data[], int length, int &num1, int &num2)
{
if (length < 2)
return;
// get num1 ^ num2
int resultExclusiveOR = 0;
for (int i = 0; i < length; ++ i)
resultExclusiveOR ^= data[i];
// get index of the first bit, which is 1 in resultExclusiveOR
unsigned int indexOf1 = FindFirstBitIs1(resultExclusiveOR);
num1 = num2 = 0;
for (int j = 0; j < length; ++ j)
{
// divide the numbers in data into two groups,
// the indexOf1 bit of numbers in the first group is 1,
// while in the second group is 0
if(IsBit1(data[j], indexOf1))
num1 ^= data[j];
else
num2 ^= data[j];
}
}
///
// Find the index of first bit which is 1 in num (assuming not 0)
///
unsigned int FindFirstBitIs1(int num)
{
int indexBit = 0;
while (((num & 1) == 0) && (indexBit < 32))
{
num = num >> 1;
++ indexBit;
}
return indexBit;
}
///
// Is the indexBit bit of num 1?
///
bool IsBit1(int num, unsigned int indexBit)
{
num = num >> indexBit;
return (num & 1);
}
给你1-1000个连续自然数,然后从中随机去掉两个,再打乱顺序,要求只遍历一次,求出被去掉的两个数
假设x,y为去掉的那俩数
result1:1^2^3^4^5………^1000
result2:1^2^3(差俩数)……^1000
result3=result1^result2=x^y
根据rusult3:的二进制的某个为1的位进行划。
因为x和y是两个不同的整数,所以这两个数的异或结果,转化为二进制的话,一定在某位是1,假设在第3位。也就是说如果把原始数组按第3位是否为0进行划分,就可以分成两个数组,每个数组各包含一个被抽取的数。如果打乱后的数组也按这个规则划分为两个数组,这样就得到了4个数组,其中两组是第3位为0,另外两组是第3位为1。把第3位为0的两个数组所有元素进行异或就能得到被抽取的一个数,同理也就能获得另外一个被抽取的数,于是问题解决。