1. 程式人生 > >[CareerCup] 10.3 Integer not Contain in the File 檔案中不包含的數

[CareerCup] 10.3 Integer not Contain in the File 檔案中不包含的數

10.3 Given an input file with four billion non-negative integers, provide an algorithm to generate an integer which is not contained in the file. Assume you have 1 GB of memory available for this task.
FOLLOW UP
What if you have only 10 MB of memory? Assume that all the values are distinct and we now have no more than one billion non-negative integers.

這道題給我們了一個很大很大的資料檔案,裡面都是有四十億個非負整數,現在給了我們1GB的記憶體大小,讓我們找到一個不包括在這個檔案中的非負整數,我們需要用位向量Bit Vector來做,跟之前那道5.8 Draw Horizonatal Line 畫橫線有些類似,題目中說資料檔案總共有四十億個數字,也就是232個,那麼非負數就有231個,給了我們1GB記憶體,也就是八十億位,我們可以把每個整數都對映到記憶體中的不同位,邏輯如下:

1. 建立一個四十億位大小的位向量Bit Vector,位向量是一個使用整型陣列來儲存bool型(或其他資料型別)值的陣列,每個整型或bool型佔32位。

2. 初始化位向量為0.

3. 遍歷所有數字,給每個數字對應的位設為1.

4. 遍歷位向量,找到第一個為0的位,算出其對應的整數。

參見程式碼如下:

class Solution {
public:
    void findOpenNumber() {
        vector<unsigned char> v(INT_MAX / 8);
        ifstream in("input.txt");
        int d;
        if (in.is_open()) {
            while (in >> d) {
                v[d 
/ 8] |= 1 << (d % 8); } in.close(); } else cout << "Cannot open file!\n"; for (int i = 0; i < v.size(); ++i) { for (int j = 0; j < 8; ++j) { if ((v[i] & (1 << j)) == 0) { cout << i * 8 + j << endl; return; } } } } };

這道題有個Follow Up,是說只給了我們10MB的記憶體大小,問如何解題。那麼既然記憶體有限,我們只能講大資料拆分為許多小的塊Block,比如說每個塊大小為1000,所以塊0為數字0到999,塊1為數字1000到1999等等。這樣我們只要先找到是哪個塊少了數字,然後再在這個塊中具體查詢少了哪個數字。下面我們就要來看每個塊大小設定為多少,給了我們10MB記憶體,也就是223個位元組,由於一個整型佔4個位元組,所以最多能有221個元素,所以我們區間大小不能小於231/221=210個,又由於10MB記憶體,也就是223個位元組,共有226位,所以每個塊可表示的數字範圍可以在210到226之間選,我們選取靠近中間的220作為數字範圍,因為越靠近中間,任意時間就會有更少的記憶體被佔用,程式碼如下:

class Solution {
public:
    void findOpenNumber() {
        int bitSize = 1048576; // 2^20 bits (2^17 bytes)
        int blockNum = 4096;
        vector<unsigned char> v(bitSize / 8);
        vector<int> b(blockNum);
        int starting = -1;
        ifstream in("input.txt");
        int d;
        if (in.is_open()) {
            while (in >> d) {
                ++b[d / (v.size() * 8)];
            }
            in.close();
        } else cout << "Cannot open file!\n";
        for (int i = 0; i < b.size(); ++i) {
            if (b[i] < v.size() * 8) {
                starting = i * v.size() * 8;
                break;
            }
        }
        ifstream in2("input.txt");
        if (in2.is_open()) {
            while (in2 >> d) {
                if (d >= starting && d < starting + v.size() * 8) {
                    v[(d - starting) / 8] |= 1 << ((d - starting) % 8);
                }
            }
            in2.close();
        }
        for (int i = 0; i < v.size(); ++i) {
            for (int j = 0; j < 8; ++j) {
                if ((v[i] & (1 << j)) == 0) {
                    cout << i * 8 + j + starting << endl;
                    return;
                }
            }
        }
    }
};