回覆列表
  • 1 # 使用者1518898301256

    可以用位向量,做集合的差集。

    儲存原理:

    在C語言中,一個字元 char 用8位二進位制編碼,實際上包含8個二進位制位,範圍

    比如由字元陣列 arrlst[n] 有如下狀態

    0 00001001

    1 10000110

    ......

    其中arrlst[0]中存的是7,6,5,4,3,2,1,0是否存在的資訊,位上面是1的表示存在,否則不存在,比如這個例子中0,3是存在的。

    類似的,arrlst[1]表示9,10,15是存在的,諸如此類。

    需要多少個arrlst呢? 為了能裝完n個數,因此需要 (n+7)<<3個arrlst數

    求差原理:

    那麼現在可以確定儲存打亂陣列的方法了,然後確定一個全集,即該全集內除了最後一個數需要特別計算外,其餘肯定都是

    然後用xor運算將兩個陣列值中,位都為1的變為0,如下例所示

    全集 comlst 中的值與相應的 我們缺了數字的集合 arrlst中值對比

    11111111

    10110111

    01001000 xor後的結果,即我們得到缺失的數其位的表示

    然後可以透過依次檢查 arrlst 異或之後不為 0 的(為0說明與全集中的情況相同,即不缺數),假設下標index,然後迴圈查詢哪個位不為0,比如可以這麼做

    1 << i 可以直接得到要檢查的位的位置,透過 & 操作得知該位是否存在

    存在則得出該行該位對應的數字 1 << (index + 1) + i;

    假設得出的數字是 10,那麼其對應

    00000100

    10對應的index = 10 << 3 = 1,在 num & (1 << 2)的時候為真,輸出

    1 << (1 +1) + 2 = 8 + 2 = 10

    集合插入原理

    那麼如何把數插入集合呢?換句話說如何在開始時的空集 arrlst 中正確的位置上將位變成 1呢?

    假如要插入 num 這個數

    首先,先求要插入的數對應於 arrlst 中的下標index = num >> 3;即除以8就行了

    然後,求arrlst[index]中對應那個位,即求餘數即可。

    我們知道一個數左移三位就是除以8,同時操作是將右邊三位擠出去,那麼餘數自然就是右邊三位了,因此我們透過 num & 7 獲得num右邊三個位的值(7 = 0b111)

    舉個例子假設有

    10010110

    00000111

    求“與”即得110即右邊三位

    餘數求出了,那麼對應於arrlst[index]的位置自然就是餘數了,因此 1 << (num & 7)就可以將1移到對應的位置上,然後取 或 操作就可以將該位置為 1了,也就相應的將數插入集合。

    總結

    這個方法空間O(n),時間O(n),但對應的n的係數因為n << 3的原因,係數並不大

    遍歷一遍原陣列,依次與全集comlst中的元素異或一遍,再遍歷一遍arrlst不為0的數的各個位即可。

    T = O(n) + O((n+7) << 3) + O(kn)(k<<1)對於缺兩個數的情況,k要遠小於1

    但這個方法最大的優勢是拓展性強,不僅可以求缺了兩個數的問題,缺了m個數的問題也同樣方法解決,程式碼都不帶變。

  • 中秋節和大豐收的關聯?
  • 歷屆奧運會的舉辦地點和時間是什麼?