有10億個整數,要求選取重複次數最多的100個整數

2021-09-30 05:30:16 字數 3588 閱讀 2213

要解答這個問題,首先要弄清楚下面幾個條件。 (

1)有記憶體限制嗎? (

2)整數的範圍是多少?有符號,無符號,

32位還是

64位? (

3)整數集的內容大嗎?(即出現的整數空間的大小大嗎?) (

4)如果只需要求模糊解,怎麼解? (

5)求陣列中的第

k大元素? (

6)相關問題:求乙個整數列**現次數最多的整數 (

7)相關問題:有乙個整數陣列,請求出兩兩之差絕對值最小的值

,記住,只要得出最小值即可,不需要求出是哪兩個數。

(1)如果沒有記憶體限制,且假設是

32位無符號的整數。最方便的辦法就是建立乙個整形陣列,

int hash[2^32]

(贊不考慮程式的虛位址空間上限),然後對這

10億個數進行一次遍歷,這樣,可以得到這

2^32

個數各自出現的次數,再對這個

hash

陣列進行取第

k大元素,

100次後,就可以取出這出現次數最多的前

100個數。遍歷

10億個數的時間複雜度是

o(n)

,n=10^10

,求第k

大元素的時間複雜度是

o(m)

,m=2^32(=4294967296)

,那麼本演算法的時間複雜度是

o(n)

,空間複雜度是

o(s)

,s=2^32

。記憶體要

2^32*4=16g (

2)如果有記憶體限制,或者必須滿足程式虛位址空間上限。那麼可以對整數空間進行分段處理,比如只提供

512m

記憶體,則將

2^32

個整數劃分成

32個空間

0~2^(27)-1

,2^(27)~2^(28)-1

,...

,31*2^(27)~2^(32)-1

。對原來的

10億個數遍歷

32次,每次遍歷,得到每個空間的整數的出現次數,並求出此空間中,出現次數最多的前

100個整數,儲存下來。這樣

32次之後,就得到了出現次數前

3200

的整數,再對這

3200

個整數取第

k大元素,得到出現次數最多的前

100個整數。這個演算法的時間複雜度也是

o(n)

,空間複雜度降低多少不知道,但是記憶體使用降低不少。 (

3)如果整數空間比較小,也就是說這

10億個數中有很多重複的數,最方便的辦法估計就是維護乙個

hashtable

物件ht

,key

就是整數值,

value

就是該整數值出現的次數。遍歷這

10億個元素,得到

ht後再對這個

ht求第

k大元素。那麼這個演算法的時間複雜度就是

o(n)

,n=10^10

,空間複雜度是

o(m),m

為整數空間大小。 (

4)隨機取樣(或者將原來的順序打亂,然後再順序取樣)。對樣本中的整數進行出現次數的統計,這個時候採用

hashtable

的辦法最好,時間複雜度是

o(n)

。如果對使用的空間有所限制,那麼只能對該樣本進行排序,再對排序後的樣本進行

100次遍歷得到出現次數最多的前

100個整數,則時間複雜度是

o(nlogn)

,空間複雜度是

o(1)。

(5)好像有兩種演算法。假設要求陣列

a[1...n]中第k

大元素。 (

a)遞迴快排演算法。若

n<44

(經驗值)則直接排序返回第

k大元素,否則,將1到

n分成n/5個組,每個組

5個元素,然後求這

n/5個組的每組的中項元素,再求這

n/5個中項元素的中項元素

mm(注意,這裡也可以用遞迴呼叫自身的方法)。然後對陣列a根據

mm分成三組,

a1中的所有元素小於mm,

a2中的所有元素等於mm,

a3中的所有元素大於

mm,如果

|a1|>=k

,則第k

大元素在

a1中,如果

|a1|+|a2|>=k|a1|,則第k

大元素就是

mm,如果

k>|a1|+|a2|

,則第k

大元素在

a3中,再繼續遞迴呼叫。這個演算法的時間複雜度是

o(n)

。(注意,這裡的中項

mm也可以隨機選擇

a中的元素,其時間複雜度也近似於

o(n)

,而且係數也比較小)。 (

b)基於位查詢(僅對於無符號整數的查詢)。將

32位整數的二進位制位分為

4段,每段

8位,先比較

a中所有元素高

8位,找出第

k大元素高

8位的範圍,再對應這高

8位的範圍在次高八位中找第

k大元素的範圍,

...這樣

4次之後就可以找到第

k大元素的。可以舉個例子便於理解,在10個

3位整數中找第

k大元素,將

3位分成

3段,每段

1位,每位之可能是0,

1。如果這

10個數的最高位

0的個數

m大於等於

k,則第

k大元素的最高位為

0,再在最高位為

0的元素中找次高位為第

k大元素;如果

10個數中最高位

0的個數m大於

k,則在最高位為

1的元素中找此高位為第

m-k大元素。

... (

6)這個問題是前面那個問題的特例。有沒有特殊的解法使效率又提高一些呢?我覺得沒有,因為1和

100本來就是常數級,和

n比它們的差別是忽略不計的。 (

7)簡單的解法是對這個陣列排序,然後再對排好序的陣列進行一次遍歷就可得到兩兩絕對值最差的最小值,時間複雜度是

o(nlogn)

。網上說求a的

min,

max和長度

n,如果

dmax = (max-min+1)/n = 0

,那麼就說明陣列

a中有重複的元素,直接返回

0。但是如果

dmax = (max-min+1)/n > 0,

那麼就以

dmax

為箱的長度裝入

a的元素,再在箱內和箱間比較。我不懂為什麼,但是這個空間複雜度是

o(max)

,而且好像如果a是

1, 2, 3...100

,那麼dmax就是1

了,那麼

a不是沒有動嗎?還有人說夠找陣列b,

b[i] = a[i] - a[i+1]

,則a[i]-a[j]=b[i]+b[i+1]+...+b[j-1]

也不知下文了,看來這個題比較搞啊。就是奧賽題,bs。

10億個數選取重複次數最多的100個整數

有10億個整數,要求選取重複次數最多的100個整數 要解答這個問題,首先要弄清楚下面幾個條件。1 有記憶體限制嗎?2 整數的範圍是多少?有符號,無符號,32位還是64位?3 整數集的內容大嗎?即出現的整數空間的大小大嗎?4 如果只需要求模糊解,怎麼解?5 求陣列中的第k大元素?7 相關問題 有乙個整...

有10億個浮點數,找出一萬個最大的數

給乙個基於最小二叉堆的方案 第一階段,向最小二叉堆中插入前一萬個浮點數 第二階段,從第一萬零乙個浮點數開始,將之與最小二叉堆頂部的最小值比較。如果小於這個最小值,把最小值彈出並將新值插入到二叉堆中。重複此過程直到遍歷完成。建立長度一萬的二叉樹。2.遍歷剩餘的浮點數,若大於最小值則插入二叉樹並刪除最小...

有10億個浮點數,從中找出1萬個最大的數。

給乙個基於最小二叉堆的方案 第一階段,向最小二叉堆中插入前一萬個浮點數 第二階段,從第一萬零乙個浮點數開始,將之與最小二叉堆頂部的最小值比較。如果小於這個最小值,把最小值彈出並將新值插入到二叉堆中。重複此過程直到遍歷完成。建立長度一萬的二叉樹。2.遍歷剩餘的浮點數,若大於最小值則插入二叉樹並刪除最小...