描述:
輸入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...