問題:找出一個數組里面前K個最大數。
解法一(直接解法):
對數組用快速排序,然后直接挑出第k大的數。這種方法的時間復雜度是O(Nlog(N))。N為原數組長度。
這個解法含有很多冗余,因為把整個數組都排序了,而實際上我們不需要這樣做。
解法二(K數組排序):
首先,創建一個長度為K的空數組。從原數組中先挑出K個數進行排序並放到這個空數組中。這一步的時間復雜度是O(Klog(K))。
接着,從剩下的N-K個值中,依次遍歷並與上面數組的末尾的數(即里面的最大數)相比較,並插入到合適位置,需要執行(N-K)步。
總平均時間復雜度是O(Klog(K)×(N-K))。
另外,如果采用最大堆或紅黑樹的方法來調整插入刪除K數組,時間復雜度是O(log(K)),總時間復雜度是O(Nlog(K))。
解法三(遞歸法):
當K值非常大或非常接近N的時候,那么上面的兩種解法的時間復雜度都會顯著增大,這就需要有更好的方法來應對:直接划定中值區間,通過比較的方法,找到第K個數所在的數值區間,然后二分搜索遞歸下去。
假設N=100萬,K=50萬的情況。
先選取一個中值元素(該中值是否合理將影響到算法效率,其原因同快速排序),然后將大於等於該數的元素放到其右側,小於該數的放到左側。如7 4 6 8 0 -1,選取6作為中值元素,則結果應該為4 0 -1 6 8 7,接下來比較K值和現在的中值元素6所在索引(3)。
如果K小於索引3,則處於包括中值元素在內的右邊的元素即是前K個最大數中的前(3(索引) - K + 1)個最大數,予以保存,同時需在索引0 ~ 2間再進行遞歸操作繼續選取第K名。
如果K大於索引3,則在4 ~ 5中遞歸選取第K - 3(索引) - 1名即可。
還有一關鍵是可以為遞歸中的數組長度選取一臨界點,小於該臨界則進行全排序,而不再進行遞歸操作。
平均時間復雜度是O(N)。
當問題規模不是很大時,比如數組大小N很小,N為100數量級,可以不用太追求算法的高效性,因為對於問題規模不大時,上面三種算法的運行時間相差並不大,
完全可以考慮采用第一種或者第二種比較簡單的實現方式。