華為OJ2051 最小的K個數(Top K問題)

2022-08-22 05:42:13 字數 1809 閱讀 1281

描述:

輸入n個整數,輸出其中最小的k個。

輸入:

輸入 n 和 k

輸入乙個整數陣列

輸出:

輸出乙個整數陣列

樣例輸入:

5 2

1 3 5 7 2

樣例輸出:

1 2

對於 top k 問題有很多種解法。

相信很多人會首先想到這種方法,先把陣列按公升序/降序進行排序,然後輸出 k 個最小/最大的數。

由於我們只需要找出最小/最大的 k 個數,所以我們可以進行部分排序,比如簡單選擇排序氣泡排序,它們每一趟都能把乙個最小/最大元素放在最終位置上,所以進行 k 趟就能把 n 個數中的前 k 個排序出來。

部分簡單選擇排序:

void select_sort(int a, int n, int k)

}}

部分氣泡排序:

void bubble_sort(int a, int n, int k)

if(flag == false) // 已經有序

return ;

}}

那麼,o(

nlog

2n) 與 o(

n∗k)

哪乙個更好呢?這取決於 k 的大小。在 k 較小的情況下,即

k<=lo

g2n,可以選擇部分排序。

根據基於快排partition操作的《第k順序統計量的求解》,我們知道,當我們求出第 k 順序統計量時,位於它前面的元素都比它小,位於它後面的元素都比它大。這時,陣列的前 k 個數就是最小的 k 個數。

int partition(int a, int low, int high)

a[low] = pivot;

return low;

}int topk(int a, int low, int high, int k)

我們說這個演算法的平均時間複雜度是線性的,更準確地說,是 o(

n∗lo

g2k)

。另外,為了避免特殊資料下的演算法退化,最好使用隨機化版本的劃分操作。

參見《堆排序》,可以用大小為 k 的大根堆來儲存最小的 k 個數。大根堆的堆頂元素就是最小 k 個數中最大的乙個。每次新考慮乙個數 x:

遍歷完成以後,陣列的前 k 個數就是最小的 k 個數,但是它們並非有序,而是以堆的形式存在。c++**如下:

void adjustdown(int a, int i, int

len)

else

break;

} a[i] = temp; // 被篩選結點的值放入最終位置

}/* 建堆 */

void buildmaxheap(int a, int

len)

/* 維護 a[0...k-1] 這個大根堆 */

void topk(int a, int n, int k)

}}

注意:找最小的

k 個數,就維護乙個大根堆;找最大的

k 個數,就維護乙個小根堆。

第二部分已經講解地很清楚了,幾種解法都可以,只要注意輸入輸出的格式就行了。

個人站點:

九度oj 1371 最小的k個數

時間限制 1 秒 記憶體限制 32 兆 特殊判題 否 提交 6191 解決 1309 題目描述 輸入n個整數,找出其中最小的k個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4,輸入 每個測試案例包括2行 第一行為2個整數n,k 1 n,k 200000 表示陣...

最小的K個數

問題描述 給定的n個整數,計算其中最小的k個數。最直觀的解法莫過於將n個數按公升序排列後輸出前k個。但是就效率來看,這種方法並不是最理想的。一種改進方法是借助快速排序中對陣列的劃分,以第k個元素對陣列進行劃分,使得比第k個數字小的數字都在其左邊,比其大的數字都在它的右邊。void swap int ...

最小的K個數

從 陣列中出現次數超過一半的數字 得到啟發,同樣可以基於partition函式來解決。一 o n 演算法 void getleastnumbers int input,int n,int output,int k else for int i 0 i k i output i input i 二 o...