問題描述:
假設有Sum=10億個關鍵字,以文件形式存儲,一行一個關鍵字。
其中有重復的。共大約有K=1億個不同關鍵字。
現在要求從這里 隨機選取 N個不同的關鍵字。
注意:隨機選取要考慮 關鍵字的頻數
N可能很小也可能很大
請設計一個 盡量高效的算法
------------------------------------------------------------------------
當前思路:
N如果較小,就按一般方式處理
N如果較大,可能需要判斷 當前選擇的關鍵字是否已經被選擇,如果被選擇過了,則需重選。這個過程的復雜度 太大
所以要盡量避免,選擇到重復的關鍵字。 直接思路是每次選擇 一個關鍵字后 就將其從被選 關鍵字集里剔除。但這里必須保證每個關鍵字被選中的概率不變。
比如 有如下關鍵字和對應頻數
A 2
B 1
C 1
D 1
在從這里選擇兩個關鍵字的前提下,A被選中的概率是:2/5*1+3/5*2/4=21/30 以此類推
如果每個關鍵字只出現一次的話,就相對容易些,維持一個線性表,在邏輯上將這個線性表看成兩部分,
前面部分是待選關鍵字集,后面是已選關鍵字集。每次隨機選擇一個關鍵字后,就把它和后面的數據交換一下。更改rand范圍即可。
但是這里每個關鍵字出現的次數是不一樣的。rand的設計不再那么簡單
總體上有那么幾個想法
1.保留重復判斷
1.1利用折半查找進行快速定位與判斷
對已選擇的關鍵字集進行折半插入排序,每次選擇了一個關鍵字后,用折半查找進行定位與判斷。
折半插入排序代價是O(N2),每次插入一個新的關鍵字
折半查找代價是O(logN)。所以時間復雜度是O(N2)
空間復雜度O(N)
1.2利用hash進行快速判斷
有點類似與數據庫cache中,頁面是否已在cache里的判斷。引入hash,鏈表等。
假設hash使用mod(N)實現
空間復雜度是O(N)
時間復雜度是O(N)
1.3保留重復判斷的一個重要問題
保留重復判斷有一個非常嚴重的問題,假設N逼近關鍵字種類數。
越到后面,隨機選擇到新的關鍵字的概率越小,需要重復隨機選擇的次數越多。
故上述方法一般適用N<<K的情況。當N->K/2時,考慮取消重復判斷,即需要構造隨機選擇
2.取消重復判斷
難點在於隨機選擇的構造,也許這個構造本身的代價也是很大的。
我想了很久,要即可行效率又不能比前面的差。
我的想法是先計算出每個關鍵字被選到的概率。
還是前面的例子A 21/30 B 1/10 C 1/10 D 1/10
rand=rand(0,sum)sum初始為1
然后麻煩的就是建立rand和i(關鍵字序號)之間的關系,這個查找過程消耗的代價也很大。
因為每次選完一個后,都要剔除,所以使用累計概率是不妥的。只能一個個比對過去,邊計算累計概率,邊比對。
概率的計算復雜度目前還沒數
后面選擇的復雜度應該是O(N)的。
