问题1:问题是一堆数,只有一个数只出现1次,其他数都出现2次,怎么求出这个数?
我们知道位运算里面的异或操作,当两个数相同时,得到的结果是零。所以我们简单的把所有数一起求异或就得到了答案。
更一般的,只有1个数出现奇数次,其他数都出现偶数次,都可以这么解决。
代码如下
class Solution { public: int singleNumber(vector<int>& nums) { int ones = 0, i; for (i = 0; i < nums.size(); ++i) ones ^= nums[i]; return ones; } }
问题2:问题是一堆数,只有2个数只出现1次,其他数都出现2次,怎么求出这个数?
基于上面的题,我们知道了,只有1个数的情况下怎么求出这个数。如果对于本题,我们用上面的方法,求出的结果是这两个只出现1次的数的异或。
我们知道如果这两个数异或结果中某一位是1,说明这2个数在这一位是不同的。因此我们可以取出这一位,然后用这一位给数分桶,两桶中的数就分别变成了问题1。
代码如下
class Solution { public: vector<int> singleNumber(vector<int>& nums) { int ones = 0, left = 0, right = 0, i; for (i = 0; i < nums.size(); ++i) ones ^= nums[i]; ones &= -ones;//取出最低不为0的一位 for (i = 0; i < nums.size(); ++i) { if (ones & nums[i]) left ^= nums[i]; else right ^= nums[i]; } return {left, right}; } };
问题2:问题是一堆数,只有3个数只出现1次,其他数都出现2次,怎么求出这个数?
基于上面的题,我们又知道了,只有2个数的情况下怎么求出这2个数。如果对于本题,我们只需要稍微改动上面的方法,就得到了答案。
用上面的方法,分桶求出后,我们得到两个数,其中一个是这三个数的某个数本身,另一个是其他两个数的异或。
如果对两个桶再分桶一次,那么包含一个数的那个桶,得到了那个数本身和0, 另外一个桶分桶就得到了剩下的两个数。
代码如下
class Solution { public: vector<int> singleNumber(vector<int>& nums) { int ones = 0, left = 0, right = 0, a = 0, b = 0, c = 0, d= 0, i; for (i = 0; i < nums.size(); ++i) ones ^= nums[i]; ones &= -ones;//取出最低不为0的一位 for (i = 0; i < nums.size(); ++i) { if (ones & nums[i]) left ^= nums[i]; else right ^= nums[i]; } left &= -left; right &= -right; for (i = 0; i < nums.size(); ++i) { if (ones & nums[i]) if (left & nums[i]) a ^= nums[i]; else b ^= nums[i]; else if (right & nums[i]) c ^= nums[i]; else d ^= nums[i]; } if (a == 0) return {b, c, d}; if (b == 0) return {a, c, d}; if (c == 0) return {a, b, d}; return {a, b, c}; } };