题目描述
一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。
leetcode对应题目:
136. 只出现一次的数字 (只有一个数字出现一次) 题目解答
137. 只出现一次的数字 II(只有一个出现一次,其余出现3次) 题目解答
260.只出现一次的数字 III(有两个数字出现了一次) 题目解答
总结:别人写的很详细了哈!我就不露怯了。关键点就是利用异或运算,然后根据不同题目的一点儿改动。这种题目大家一开始都会想到用哈希表,但是这就相当于做题没有充分利用给定的条件,如果这时候面试官对时间复杂度,空间复杂度有要求的话就糟糕了。
异或的性质:任何一个数字异或它自己都等于0.
“268缺失的数字”一题,实际上就是一个数组只有一个数出现一次,其余数出现两次的思想,只是因为题目给定数字范围"0~n"这样就可以正好利用for(...)循环中的数字相异或。注意!是从1~n还是从0~n,写法上要注意一点。不过核心就是要把0~n或者1~n的数字都相异或了。
其实最关键的是:为什么凭借n&~n就能找到一个区分两个只出现一次的数字?
首先要知道n&~n的意义是如何求一个二进制数的最低位的1在哪里。
又因为这个数是根据只出现一次的数a,b异或而来,也就是说最低位的1肯定是a,b的最低位异或来的,就是说a,b之间肯定有一个最低位是0,一个是1,所以根据这种情况就能分开这两个数了。
class Solution {
public:
void FindNumsAppearOnce(vector<int> data,int* num1,int *num2) {
if(!data.size()) return ;
int dif = 0;
for(int i = 0;i<data.size();i++){
dif ^= data[i];
}
dif &= -dif;//进行 a &= -a 操作。首先变负数吧,在二进制中负数采用补码的形式,而补码就是反码 +1
//这个操作之后可以找到两个不相同数的不相同的位.
//比如1,1,2,2,...,3,5,dif = 110 dif &= -dif dif = 010
//可知3 和 5 在从低位开始的第二位不同.010
//所以根据这一位的差异来区别两个数
for(int i = 0;i<data.size();i++){
if(dif & data[i])
*num1 ^= data[i];//其它成对出现的数异或两次不变。剩下就是单独出现的。
else
*num2 ^= data[i];
}
}
};