LeetCode.260 Single Number 3

寫作來源

今天在LeetCode上面連續做了Single Number 2和Single Number 3,非常羞恥地說,兩題都是看了別人的思路理解以後再寫出來的,Single Number 2的解法有人已經在簡書上面寫了,我這裏就解釋一些LeetCode上面的Discuss部分的其他人的解法。

思路

首先貼上別人寫的代碼。

class Solution
{
public:
    vector<int> singleNumber(vector<int>& nums) 
    {
        // Pass 1 : 
        // Get the XOR of the two numbers we need to find
        int diff = accumulate(nums.begin(), nums.end(), 0, bit_xor<int>());
        // Get its last set bit
        diff &= -diff;

        // Pass 2 :
        vector<int> rets = {0, 0}; // this vector stores the two numbers we will return
        for (int num : nums)
        {
            if ((num & diff) == 0) // the bit is not set
            {
                rets[0] ^= num;
            }
            else // the bit is set
            {
                rets[1] ^= num;
            }
        }
        return rets;
    }
};

第一步,如果說寫了Single Number的人首先會把所有的數進行異或,最終得到兩個不重複兩次的數字的異或的結果,這裏記爲:

diff=b0xorb1 d i f f = b 0 x o r b 1

此時,設所有重複了兩次的數字分別爲

a0,a1,a2an a 0 , a 1 , a 2 ⋯ a n ,而本題的思想就是通過某一種標識把

b0 b 0

b1 b 1 分離,或者說是把整個輸入的列表分成兩個部分,這兩個部分分別爲:


c0,c1cm,b0d0,d1dk,b1{a0,a1,a2an}={c0,c1cm}{d0,d1dk}(523) (523) c 0 , c 1 ⋯ c m , b 0 d 0 , d 1 ⋯ d k , b 1 { a 0 , a 1 , a 2 ⋯ a n } = { c 0 , c 1 ⋯ c m } ∪ { d 0 , d 1 ⋯ d k }

因爲集合中沒有重複的數字,所以這裏爲了表示重複數字,加上上標表示重複,即比如

a0 a 0 的兩個重複值爲

a10 a 0 1

a11 a 1 1 ,所以在上面的兩個集合中,存在:


c00xorc10xorc01xorc11xorxorb0=b0d00xord10xord01xord11xorxorb1=b1(524) (524) c 0 0 x o r c 0 1 x o r c 1 0 x o r c 1 1 x o r ⋯ x o r b 0 = b 0 d 0 0 x o r d 0 1 x o r d 1 0 x o r d 1 1 x o r ⋯ x o r b 1 = b 1

由上面的代碼可以看出來,這個標識符爲

diff d i f f ,原因是,通過

diff=diffxor(diff) d i f f = d i f f x o r ( − d i f f ) 計算以後,

diff d i f f 的值只保留了原本的數的最低位,其他的位的值都是0,這算是位運算中最基本的技巧吧。也就是說,原本的

diff d i f f 的最低位也是1,從而推斷

b0 b 0

b1 b 1 的相應位肯定分別爲

0 0

1 1 ,因爲只有兩個位的值不一樣才能夠異或出

1 1 。這就說明

diff d i f f 的值是可以作爲標識符的。

其實這裏我們可以不用管上面所說的

c0,c1cm c 0 , c 1 ⋯ c m

d0,d1dk d 0 , d 1 ⋯ d k 分別是多少,反正也會被這個標識符分成兩個集合,我們只需要關心能被分成兩個集合即可。

点赞