拜託,面試別再問我TopK了!!!

2021-09-20 02:19:21 字數 2117 閱讀 4449

除非校招,我在面試過程中從不問topk這個問題,預設大家都知道。:

: 將n個數排序之後,取出最大的k個

,即為所得。 :

sort(arr, 1, n);

return arr[1, k];

:o(n*lg(n))

:明明只需要topk,卻將全域性都排序了,這也是這個方法複雜度非常高的原因。

那能不能不全域性排序,而只區域性排序呢?

這就引出了第二個優化方法。

每冒乙個泡,找出最大值,冒k個泡,就得到topk。

for(i=1 to k)

return arr[1, k];

:o(n*k)

:冒泡,將全域性排序優化為了區域性排序,非topk的元素是不需要排序的,節省了計算資源。不少朋友會想到,需求是topk,是不是

這最大的k個元素也不需要排序呢?

這就引出了第三個優化方法。

:只找到topk,不排序topk。

這個小頂堆用於儲存,當前最大的k個元素。

如果被掃瞄的元素大於堆頂,則替換堆頂的元素,並調整堆

,以保證堆內的k個元素,總是當前最大的k個元素。

heap[k] = make_heap(arr[1, k]);

for(i=k+1 to n)

return heap[k];

:o(n*lg(k))

:堆,將冒泡的topk排序優化為了topk不排序,節省了計算資源。堆,是求topk的經典演算法,

那還有沒有更快的方案呢?

快速排序。

void quick_sort(intarr, int low, inthigh)

分治法。

(divide&conquer),

把乙個大的問題,轉化為若干個子問題

(divide),

每個子問題「」解決

減治法。

(reduce&conquer),

把乙個大的問題,轉化為若干個子問題

(reduce),

這些子問題中「」解決乙個

,bs,是乙個典型的運用

減治法思想的演算法,其偽**是:

int bs(intarr, int low, inthigh, int target)

分治法的複雜度一般來說是大於減治法的:

核心是:

i = partition(arr, low, high);

右半部分,都比t小

中間位置i是劃分元素

右半區比t小

中間是t

最終的位置i。

最大的k個數

,那如果找到了第k大的數

,做一次partition,不就一次性找到最大的k個數了麼?

找到第k大的數。

i = partition(arr, 1, n);

如果i小於k,則說明說明第k大的元素在arr[i]的右邊,於是只遞迴arr[i+1, n]裡第k-i大的元素即可;

int rs(arr, low, high, k)

,大問題分解為小問題,小問題都要遞迴各個分支,例如:快速排序

減治法,大問題分解為小問題,小問題只要遞迴乙個分支,例如:二分查詢,隨機選擇

,o(n*lg(n))

區域性排序,只排序topk個數,o(n*k)

,topk個數也不排序了,o(n*lg(k))

分治法,每個分支「都要」遞迴,例如:快速排序,o(n*lg(n))

減治法,「只要」遞迴乙個分支,例如:二分查詢o(lg(n)),隨機選擇o(n)

topk的另乙個解法:隨機選擇+partition

原文發布時間為:2018-09-20

拜託,面試別再問我跳表了!

跳表是乙個隨機化的資料結構,實質就是一種可以進行二分查詢的有序鍊錶。跳表在原有的有序鍊錶上面增加了多級索引,通過索引來實現快速查詢。跳表不僅能提高搜尋效能,同時也可以提高插入和刪除操作的效能。考慮乙個有序鍊錶,我們要查詢3 7 17這幾個元素,我們只能從頭開始遍歷鍊錶,直到查詢到元素為止。上述這個鍊...

拜託,面試別再問我計數排序了!!!

radix sort 還有計數排序 counting sort 今天,1分鐘,通過幾幅圖,爭取讓大家搞懂計數排序。空間大小為o max min 用來儲存所有元素出現次數 計數 掃瞄待排序資料 arr n 使用計數陣列 counting max min 對每乙個 arr n 現的元素進行計數 掃瞄計數...

拜託,面試別再問我時間複雜度了!!!

分為這麼幾步 先做一次partition 左半區遞迴 右半區遞迴 partition arr,low,high quick sort arr,low,i 1 quick sort arr,i 1,high 通過了乙個中間變數t,進行了3次操作,交換了a和b的值,swap的時間複雜度是o 1 通過乙個...