尝试说明大家普遍使用的一种方法:利用位运算来实现。
三步走:
1.首先将数组元素依次异或,得到值resultExclusiveOR,接下来要利用这个数字将原数组分为两部分。
2.利用子函数FindFirstBitIs1()来找FindFirstBitIs1中第一次出现1的位,假设为b位。
3.接下来就是利用函数IsBit()来实现区分b位为1的一组,不为1的是另一组。
class
Solution {
public
:
void
FindNumsAppearOnce(vector<
int
> data,
int
* num1,
int
* num2) {
if
(data.size() < 2)
return
;
int
resultExclusiveOR = 0;
for
(
int
i = 0; i < data.size(); i++){
resultExclusiveOR ^= data[i];
}
unsigned
int
indexOf1 = FindFirstBitIs1(resultExclusiveOR);
*num1 = *num2 = 0;
for
(
int
j = 0; j < data.size(); j++){
if
(IsBit1(data[j], indexOf1))
*num1 ^= data[j];
else
*num2 ^= data[j];
}
}
unsigned
int
FindFirstBitIs1(
int
num){
int
indexBit = 0;
while
(((num & 1) == 0) && (indexBit < 8*
sizeof
(
int
))){
num = num >> 1;
indexBit++;
}
return
indexBit;
}
bool
IsBit1(
int
num, unsigned
int
indexBit){
num = num >> indexBit;
return
(num&1);
}
};
怎么实现的呢,刚开始我也是一头雾水,但是仔细看一会发现,例如,2,3,4,4,5,5,二进制代码依次为10,11,100,100,101,101。将他们依次异或(^)后,结果为01,显然相同的4和4,5和5根本不影响不相同的数2和3之前的异或,这是一点,假如2,4,4,5,5.异或之后结果10,即2;3,4,4,5,5。异或之后结果为11,即3,;好了这一个异或解决了两个问题,找到单独存在的数和如何提出来单独的数,只要把单独存在且不同的两个数分到两个数组里然后异或,结果就是我们要的,怎么分数组,整体数组异或结果位出现1可以说明原来两个不同的数在这一位是不同的,那这个突破点就找到了,只要从右到左找到第一个1所在位,然后按照在这一位是1为标准划分为两个数组就可以了。举个例子更形象,7和10,二进制依次为0111和1010,异或结果为1101,只要把二进制第一位是1的分到A数组,不是1的分到B数组,就自然把7和10分到两个数组了。