1. 程式人生 > >LeetCode 260 Single Number III(只出現一次的數字 III)(*)

LeetCode 260 Single Number III(只出現一次的數字 III)(*)

原文

給定一個數字陣列nums,其中有兩個元素只出現一次,而其他所有元素均出現兩次。

找出這兩個只出現一次的元素。

例如:

給定nums = [1, 2, 1, 3, 2, 5],返回[3, 5]。

備註:
1, 返回結果的順序不重要。所以在上例中,返回[3, 5]也是正確的。
2, 你的演算法應該執行線上性時間複雜度。你可以只用常量空間複雜度來實現它嗎?

原文

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: 1. The order of the result is not important. So in the above example, [5, 3] is also correct. 2. Your algorithm should run in linear runtime complexity. Could you implement it using only constant
space complexity?

分析

本題我曾在《劍指Offer》中見過,記得要用位運算,自己實現了一遍,不過再看了看書上的,並沒有書上的規範,所以最後貼了書上的程式碼……

其實有這麼一個性質:

任何數字異或其自身都等於零。

可能有讀者不瞭解什麼是異或,那麼就來插播一下:

異或,英文為exclusiveOR,或縮寫成xor,異或是一個被用於邏輯運算的數學符號。其數學符號是“⊕”,計算機符號是“xor”。

a⊕b=(¬a∧b)∨(a∧¬b)

true ⊕ false -> true
false ⊕ true -> true
true ⊕ true -> false
false ⊕ false -> false

也就是說兩個值相同則異或結果為假,兩個值不同則異或為真。所以任何數字異或其自身都等於零,因為兩個值相同。

好了,切入正題。就以題目中給出的陣列為例吧:

[1, 2, 1, 3, 2, 5, 6, 5, 4, 6]

分別換算成二進位制如下:
00010010000100110010
01010110010101000110

對所有陣列進行異或運算得出的結果是:0111

於是進行分組如下:
A組: 00011)、00102)、00011)、00113)、00102)
B組: 01015)、01106)、01016)、01004)、01105)

對A組進行再次異或運算的結果是:00113)

對B組進行再次異或運算的結果是:01004

判斷該數字的二進位制第n位是否是1的函式:

bool IsBit1(int num, unsigned int index) {
    num = num >> index;
    return (num & 1);
}`

找出該數字二進位制中第一個1的函式:

unsigned int FindFirstBigIs1(int num) {
    int indexBit = 0;
    while (((num & 1) == 0) && (indexBit < 8 * sizeof(int))) {
        num = num >> 1;
        ++indexBit;
    }
    return indexBit;
}

根據LeetCode的函式模板修改了一點:

vector<int> singleNumber(vector<int>& nums) {
    vector<int> singleV;
    if (nums.size() <= 0) return singleV;

    int resultExclusiveOR = 0;
    for (int i = 0; i < nums.size(); ++i)
        resultExclusiveOR ^= nums[i];

    unsigned int indexOf1 = FindFirstBigIs1(resultExclusiveOR);

    int singleNum1 =0, singleNum2 = 0;
    for (int j = 0; j < nums.size(); ++j) {
        if (IsBit1(nums[j], indexOf1))
            singleNum1 ^= nums[j];
        else
            singleNum2 ^= nums[j];    
    }

    singleV.push_back(singleNum1);
    singleV.push_back(singleNum2);
    return singleV;
}

還有兩道相關的題: