Given an array of numbers nums
, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once.
For example:
Given nums = [1, 2, 1, 3, 2, 5]
, return [3, 5]
.
Note:
- The order of the result is not important. So in the above example,
[5, 3]
is also correct. - Your algorithm should run in linear runtime complexity. Could you implement it using only constant space complexity?
这种题的思路其实都差不多……
如果其他数都出现两次,只有一个数出现一次的话,那么出现两次的数异或为0,整个数组异或结果就是数a。
如果有两个数a,b都出现一次的话,那么整个数组异或的结果c就是这两个数异或的结果。 我们需要把这两个数分到两组里面,这样的话每组异或的结果就分别是这两个数了。那么办怎么做呢?
其实很简单,这两个数既然不一样的话,那么异或的结果必然有一位为1(就是两个数不一样的位数),通过c & -c得到这个数之后再对数组进行遍历,只要n & c & -c为真,那么这些数属于一类,将它们异或起来的结果就是数a或者b。
求另一个数的方法可以是当n & c & -c 为假时异或,也可以利用刚刚的异或结果c ^ 为真的结果。 因为 c = a ^ b, c ^ b = a ^ b ^ b = a
还有一种情况是升级版,每个数出现三次,只有一个数出现一次,求这个数。这个就不能用异或了。可以对int的32位分别遍历数组,因为每个数出现3次,因此如果除去所求的n的话,每位上的1的个数%3应当 = 0. 因此如果该位上统计得到的1的个数%3 = 0的话,证明n的这位为0, 反之则为1.
class Solution {
public:
vector<int> singleNumber(vector<int>& nums) {
int a = 0, b = 0;
for(auto n : nums) a ^= n;
for(auto n : nums) if(n & a & -a) b ^= n;
return vector<int> {a ^ b, b};
}
};