題目描述:查詢最小的k個元素
題目:輸入n個整數,輸出其中最小的k個。
例如輸入1,2,3,4,5,6,7和8這8個數字,則最小的4個數字為1,2,3和4。
1:最簡單直白的思路是,要求乙個序列中最小的k個數,按照慣有的思維方式,很簡單,先對這個序列從小到大排序,然後輸出前面的最小
的k個數即可。
至於選取什麼的排序方法,可能會第一時間想到快速排序,我們知道,快速排序平均所費時間為n*logn,然後再遍歷序列中前k個元素輸出,即可,總的時間複雜度為o(n*logn+k) =o(n*logn)。
線性時間的排序,即計數排序,時間複雜度雖能達到o(n),但限制條件太多,不常用。
2:再進一步想想,題目並沒有要求要查詢的k個數,甚至後n-k個數是有序的,既然如此,咱們又何必對所有的n個數都進行排序列?
這時,可以如此:即遍歷n個數,先把最先遍歷到得k個數存入大小為k的陣列之中,對這k個數,利用選擇或交換排序,找到k個數中的最大數kmax,用時o(k),後再繼續遍歷後n-k個數,x與kmax比較:如果x>kmax,則不更新陣列;如果x這樣,被交換出的kmax至少大於k個數,所以肯定不是最終結果中的數。)這樣,整趟下來,總的時間複雜度平均下來為:n*o(k)=o(n*k)。
上述思想的乙個優化,就是維護k個元素的最大堆(大小是k),原理與上述第方案一致,即用容量為k的最大堆儲存最先遍歷到的k個數,建堆費時o(k)後。繼續遍歷數列,每次遍歷乙個元素x,與堆頂元素比較,xo(n*logk)。此方法得益於在堆中,查詢等各項操作時間複雜度均為logk。
3:實際上,可以用最小堆初始化數
組(大小是n,不是k),然後取這個優先佇列前k個值。複雜度o(n)+k*o(log n)。建堆所用時間為o(n),然後取堆中的前k個數,總的時間複雜度即為:o(n+k*logn)。至於該思路的時間是否小於上述思路的o(n*logk),即o(n+k*logn)可以這麼解決:當k是常數,n趨向於無窮大時,求(n*logk)/(n+k*logn)的極限t,如果 t>1,那麼可得o(n+k*logn)< o(n*logk)。最終證明的確如此,這個極值t=logk>1,即採取建立n個元素的最小堆後取其前k個數的方法的複雜度小於採取常規的建立k個元素最大堆後通過比較尋找最小的k個數的方法的複雜度。
事實上,是建立最大堆還是建立最小堆,其實際的程式執行時間相差並不大,執行時間都在乙個數量級上。
但是當n比較大時(海量資料),那麼需要將n個數都建立最小堆,這個時候,就不如建立k個元素的最大堆適用了。
4:演算法導論第9章,曾介紹randomized-select(a,p, r, i)演算法,該演算法可以尋找第i小的數,該演算法用類似快速排序的劃分方法,n個數儲存在陣列s中,再從陣列中隨機選取乙個數x,把陣列劃分為sa和sb倆部分,sa<=x<=sb,如果i小於sa的元素個數,則遞迴呼叫randomized-select(a,p, q-1, i),否則呼叫randomized-select(a, q+1, r, i-k)。
a:找到了第k小的數x後,再遍歷一次陣列,找出所有比x小的元素,需要o(n)的時間(比較xk與陣列中各數的大小,凡是比xk小的元素,都是我們要找的元素)。這個結論非常之簡單,也無需證明。
b:找到第k小的元素x後,因為討論都是基於快速排序的partition方法,而這個方法,每次劃分之後,都保證了樞紐元素x的前邊元素統統小於xk,後邊元素統統大於xk。所以,演算法本身,在找到第k小的元素之後,之前的元素就是所有最小的k個元素。
randomized-select,以序列中隨機選取乙個元素作為主元,可達到線性期望時間o(n)的複雜度。select,快速選擇演算法,以序列中「五分化中項的中項」,或「中位數的中位數」作為主元(樞紐元),則不容置疑的可保證在最壞情況下亦為o(n)的複雜度。
至於randomized-select(a, p, r, i)演算法,以及最壞情況下為o(n)的select演算法,演算法導論第9章都有詳述,不再贅述。
尋找最小的k個數
尋找最小的k個數 在乙個長度為n的陣列中,尋找最小的k個數。最大的k個數解法類似 想法比較簡單,先對n個數排序,再輸入前面k個數,即可。這種方法的時間複雜度比較大。假設我們使用快排,需要o nlogn 然後輸出k個數需要o k 一共要o nlogn 略。這種方法比較好,演算法簡單,易於實現。先把陣列...
尋找最小的k個數
輸入n個整數,輸出其中最小的k個。要求乙個序列中最小的k個數,按照慣有的思維方式,則是先對這個序列從小到大排序,然後輸出前面的最小的k個數。至於選取什麼的排序方法,我想你可能會第一時間想到快速排序 我們知道,快速排序平均所費時間為n logn 然後再遍歷序列中前k個元素輸出即可。因此,總的時間複雜度...
尋找最小的 k 個數
輸入n個整數,輸出其中最小的k個。使用排序的方法來解決該問題。快速排序所費時間複雜度為o n logn 排序完成過後,只需要取前k個數值即是最小的k個數。int array const int length sizeof array sizeof array 0 void printarray in...