题目详情
一个整型数组 nums
里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例 1:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
示例 2:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
限制:
2 <= nums <= 10000
——题目难度:中等
思路
解决这题并且用到异或解法需要以解决136. 只出现一次的数字和与运算为基础。
解题顺序
1.先对全员进行异或操作,这样ret就是两个出现一次数字的异或后的结果
2.要想从ret中逆推出那两个只出现一次的数字
就需要进行分组:
① 两个只出现一次的数字在不同的组中
② 相同的数字会被分到相同的组中
②比较好解决,主要是①。
要解决①的话,需要先知道两个出现一次数字的不同点,不同点即一定在某一位上不同(转化为二进制时,如一个数字某一位上是1, 另一个数字那一位为0),而正好两个数异或的结果就是两个数数位不同的直观表现(0即相同,1即不同)
我们可以置一个变量mark(设初值为1)来找到两个数字的数字不同的最低位,通过"while( (ret&mark)==0 ) mark=mark<<1;"循环即可找出这个最低位。
3.随后通过这个最低位可以分别找出那两个只出现一次的数字,还可以满足分组条件②(因为两个相同的数被一个相同条件选择后一定会分到一个组去)。
-下面代码
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
int n = nums.size(), ret=0, mark=1, a=0,b=0;
for(int i=0;i<n;i++) //对全员和0做异或处理
ret = ret^nums[i];
while( (ret&mark)==0 ){ //找到数字不同的最低位
mark=mark<<1;
}
for(int i=0;i<n;i++)
{
if( (nums[i]&mark)==0 ){
a = a ^ nums[i];
}else{
b = b ^ nums[i];
}
}
return vector<int>{a,b};
}
};
结果