可以用位向量,做集合的差集。
儲存原理:
在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個數的問題也同樣方法解決,程式碼都不帶變。
可以用位向量,做集合的差集。
儲存原理:
在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個數的問題也同樣方法解決,程式碼都不帶變。