題目
給定一個整數數組 nums,其中恰好有兩個元素只出現一次,其餘所有元素均出現兩次。 找出只出現一次的那兩個元素。
示例 :
輸入: [1,2,1,3,2,5]
輸出: [3,5]
注意:
結果輸出的順序並不重要,對於上面的例子, [5, 3] 也是正確答案。
你的算法應該具有線性時間複雜度。你能否僅使用常數空間複雜度來實現?
來源:力扣(LeetCode)
思路
首先,將其全部位進行 ‘異或’ ,我們知道相同的兩個數 ‘異或’ 的話爲0,那麼數組中的1和2,都抵消掉了,就剩3和5 ‘異或’ 起來,那麼就是二進制的 11 和 101 ‘異或’ ,得到110。
然後,進行 a &= -a 操作。首先變負數吧,在二進制中負數採用補碼的形式,而補碼就是反碼 +1,那麼 110 的反碼是 11…1001,那麼加1後是 11…1010,然後和 110 相與,得到了 10,就是代碼中的 diff 變量。得到了 diff,就可以將原數組分爲兩個數組;
如果兩個相同的數字 ‘異或’ ,每位都會是0,而不同的數字 ‘異或’ ,一定會有對應位不同,一個0一個1,這樣 ‘異或’ 是1。
比如3和5的二進制 11 和 101,如果從低往高看,最開始產生不同的就是第二位,用第二位來和數組中每個數字相與,根據結果的不同,一定可以把3和5區分開來;
而其他的數字由於是成對出現,所以區分開來也是成對的,最終都會 ‘異或’ 成0,不會3和5產生影響;
分別將兩個小組中的數字都異或起來,就可以得到最終結果。
C++代碼
class Solution {
public:
vector<int> singleNumber(vector<int>& nums)
{
int diff = accumulate(nums.begin(), nums.end(), 0, bit_xor<int>());
diff &= -diff;
vector<int> res(2, 0);
for (auto &a : nums)
{
if (a & diff)
res[0] ^= a;
else
res[1] ^= a;
}
return res;
}
};