第40题 数组中只出现一次的数字
题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
int ret =0 ;
for(const int k : data){
ret ^= k;
}
ret &= (-ret);
*num1 = 0, *num2 = 0;
for(const int k : data){
if(k & ret) *num1 ^= k;
else *num2 ^= k;
}
}
};
class Solution:
def singleNumbers(self, nums: List[int]) -> List[int]:
ret = 0
for n in nums:
ret ^= n
ret &= -ret
n1 = n2 = 0
for n in nums:
if n & ret:
n1 ^= n
else:
n2 ^= n
return [n1, n2]
思路:
利用位异或的性质
n^0 = n;
n^n = 0;
n^ n^ m = n^ (n^m) 满足交换律
位异或的位值取决于该位上1的个数的奇偶,奇数为1,偶数为0。
因为其他出现两次,位异或就抵消掉只有我们要的两个数字,得到的结果ret是两个不同数字的位异或的结果。
既然是两个不同的数字,那么这两个数字肯定在某一位上存在不同值情况,即一个在该位置是1,另一个是0,这个位置肯定是ret等于1的位置(因为不同值异或结果为1),为了找到这个位置,我们将ret与-ret作位与操作,因为补码的关系,负数是整数的除符号位的按位取反加1,比如0010,1110,我们就可以找到ret从左往右第一个为1的位置,位与结果就是该位置为1,其余位置为0。
于是我们将这些数分为两类,一类该位置为1,另一类为0,再做异或操作就可以分别得到这样两个值了。