[CareerCup] 5.7 Find Missing Integer 查詢丟失的數

Grandyang發表於2015-08-21

 

5.7 An array A contains all the integers from 0 to n, except for one number which is missing. In this problem, we cannot access an entire integer in A with a single operation. The elements of A are represented in binary, and the only operation we can use to access them is "fetch the jth bit of A[i]," which takes constant time. Write code to find the missing integer. Can you do it in 0(n) time?

 

這道題給我們一個0到n的陣列,然後其中一個數丟失了,讓我們找到這個數。一個比較容易想到的方法是先用高斯求和公式求出等差數列0到n的和,然後遍歷陣列求所有數字之和,那麼差值就是結果。但是這個解法就沒有用到高大上的位操作Bit Manipulation,也許也不是出題人想考察的方法。題目中說了所有的整型數都是以二進位制數表示的,而且可以以O(1)的時間來訪問任意一位,這也很明顯的提示了我們用位操作。我們先來看一個n=13的例子,那麼0到13的二進位制數表示如下:

00000        00100        01000        01100
00001        00101        01001        01101
00010        00110        01010
00011        00111        01011

然後我們觀察上面的數字的最低有效位Least Significant Bit (LSB),然後我們統計1和0的個數,我們可以得出一個規律,當n是奇數時,0和1的個數相等,當n是偶數時,0比1多一個。那麼當我們移除一個數的話,就有下面四種情況:

 

N為偶數,0比1多一個

N為奇數,0和1個數相等

移除0

0和1個數相等

0比1個數少

移除1

0比1個數多

0比1個數多

從上表可以看出來我們比較LSB的1和0的個數就可以知道移除的是1還是0,只要0的個數小於等於1,就是移除0,若0的個數大於1,就是移除1.我們一旦知道最低有效位移除的值,那麼把所有不符合要求的都去掉,然後再用相同方法來判斷倒數第二低有效位,以此類推直到所有的數字都被移除了,具體過程參見如下,當n=13,且移除了一個數:

00000        00100        01000        01100
00001        00101        01001        01101
00010        00110        01010
------           00111        01011

那麼我們來統計最低有效位的0和1的個數,發現0比1個數多,由此我們知道移除的數的最低有效位是1,那麼我們把所有最低有效位是0的數都去掉:

00000        00100        01000        01100
00001        00101        01001        01101
00010        00110        01010
------           00111        01011

我們再來統計倒數第二低有效位的0和1的個數,我們發現0比1個數多,那麼移除數的倒數第二低有效位還是1,同樣把其他的去掉:

00000        00100        01000        01100
00001        00101        01001        01101
00010        00110        01010
------           00111        01011

我們再來統計倒數第三低有效位的0和1的個數,我們發現0比1個數相等,那麼移除數的倒數第三低有效位是0,同樣把其他的去掉,那麼就只剩下一個了:

01011

那麼倒數第四低有效位的0比1個數小,移除的是0,在把這個不是0的刪掉,則陣列為空了,我們就可以停止了,把所有移除的組合起來就得到0011,也就是最後的答案了,參見程式碼如下:

 

class Solution {
public:
    int findMissing(vector<int> nums) {
        return findMissing(nums, 0);
    }
    int findMissing(vector<int> nums, int col) {
        if (nums.empty()) return 0;
        vector<int> oneBits, zeroBits;
        for (auto &a : nums) {
            if (fetch(a, col) == 0) zeroBits.push_back(a);
            else oneBits.push_back(a);
        }
        if (zeroBits.size() <= oneBits.size()) {
            int v = findMissing(zeroBits, col + 1);
            return (v << 1) | 0;
        } else {
            int v = findMissing(oneBits, col + 1);
            return (v << 1) | 1;
        }
    }
    int fetch(int n, int col) {
        return n & (int)pow(2, col);
    }
};

 

相關文章