本來今天想寫的是「面試記」,八一八hr姐姐和面試官叔叔。但聊到面試難免要聊面試題,而演算法題自是其重中之重。為了日後能專心地八面試官,今天就先說說這個演算法。。。
本篇涉及專業知識,外行止步,發生危險概不負責。
問題:[random select]求已知n個數中第k小的數。(k
先排序再取數的做法需要o(n*logn)的複雜度,事實上此問題o(n)可解。具體做法是:按照類似快速排序算 法中的「分類」步驟,任選乙個參考數,把整個陣列分成左右兩部分。左邊部分小於參考數,右邊部分大於參考數。然後根據左右部分各自包含元素的個數,計算出 要求的元素在哪個陣列中。(要求的元素或者是左陣列中的第k小數,或者是右陣列中第[k-l]小的數。l為左陣列的長度)然後遞迴之。
貼個偽**:
int select(int arr, int lw, int hi, int k)
// lw:下標下界, hi:下標上屆。
如果有乙個陣列,對其取中位數,然後移除此元素。重複此操作k次,求這k個被移除的數。如何設計演算法?
(注,當陣列長度為偶數時,中位數有兩種不同的定義。此處定義第[n/2]個數為中位數,而不是中間兩數之平均。)
也許不可思議,此問題仍然有o(n)的解法:
可以證明:如果將陣列排序,那麼問題等價於求陣列最中間的一段k個數。當然「最中間一段」這樣的說法有些含糊,但大致上就是求下標為[n/2-k/2, n/2+k/2]這個區間上的一段數,但是在區間兩端要根據n和k的奇偶性作+1或-1的調整。因此,原問題轉化為:
求某個陣列中第a小到第b小之間的k個數。(b>=a,k==b-a+1)
剩下的問題就很簡單了:先求原陣列中最小的b個數,然後在此結果中求最大的(b-a+1)個數。
最後乙個推廣,此演算法還可以用在著名的「主元素」問題上。主元素的定義是:
如果乙個陣列中,有乙個數出現次數達到陣列長度的一半以上,則稱其為陣列的
主元素。
主元素問題就是:
給定乙個陣列,判斷其是否有主元素,並求這個元素。
N個數,求第K大數
有n個不重複的數,這n個數可以放入記憶體中,讓你用最快的方法找到第k大的數。解答 一般情況我們可能考慮,先將n個數排序 快排序 堆排序 然後可以得到結果。但是當n很大時這樣做的效率會很低。所以我們提出一種更高效的方法 利用快速排序的特點 第一遍排序會確定乙個數的位置,這個數左邊都比它大,右邊都比他小...
N個數,求第K大數
今天同學給我出了一道題是這樣的 有n個不重複的數,這n個數可以放入記憶體中,讓你用最快的方法找到第k大的數。解答 一般情況我們可能考慮,先將n個數排序 快排序 堆排序 然後可以得到結果。但是當n很大時這樣做的效率會很低。所以我們提出一種更高效的方法 利用快速排序的特點 第一遍排序會確定乙個數的位置,...
線性選擇 求n個數中第k小數
include include include template int partition type a,int p,int r a p a j a j x return j template int randamizedpartition type a,int p,int r template ...