單峰陣列實際上可以看成兩個有序的陣列,這個問題就轉變成了兩個有序陣列求第k大。
容易想到的演算法是對這兩個陣列進行歸併,生成乙個新的有序陣列,求出第k大之後就可以立刻停止,複雜度是o(k)的。
但是還有更優的演算法,可以使用分治的思想(實際上也是一種二分)來計算。
對於兩個有序的陣列a和b,取出他們第k/2個元素進行比較,這種時候就會產生大於、小於和等於三種情況,對於這三種情況:
1、a的取出元素大於b的取出元素
說明b中的前k/2個元素全部小於a的第k/2個元素,第k大一定不在b的前k/2個中,因此這一部分可以全部丟掉,到剩下的部分中去找第k - k/2大。
2、小於的情況,和1剛好相反,丟棄a的前k/2個,去找剩下的k - k/2。
3、相等的情況。
相等的情況比較複雜,如果k是偶數,那麼此刻就已經獲得了第k大(a陣列k/2個,b陣列k/2個,加起來剛好k個),直接返回即可,奇數則需要比較a、b陣列的下乙個數,返回小的那個。
但是這樣討論比較挫,相等的情況實際上可以被包含在上面兩種情況的**裡處理掉,除非空間和時間要求特別大,可以忽略掉。
然後就是某個陣列出現了不足以取k/2個的情況,那麼很顯然,第k大不在這個陣列裡,可以直接減掉這一部分,去另外乙個陣列找。
到了最後,k等於1時,就找到了第k大,返回兩個陣列當前位置的最小值即可。
這樣的演算法用迴圈實現起來真的是難寫,但是用遞迴寫起來就很舒服了,確定好兩個起始位置之後一直往下遞迴就完事了。
**:
#include
using namespace std;
const
int maxn =
1e5+5;
const
int inf =
1e9+7;
int a[maxn]
, b[maxn]
, mid, n;
intkth
(int s1,
int s2,
int k)
if(s2 >= n - mid)
if(k ==1)
int end1 = inf, end2 = inf;
if(s1 + k /2-
1< mid)
if(s2 + k /2-
1< n - mid)
if(end1 < end2)
return
kth(s1, s2 + k /
2, k - k /2)
;}/*8
1 2 4 8 7 3 3 2
*/int
main()
for(
int i =
0; i < n - mid; i++
)while
(cin >> k)
return0;
}
求序列第K大演算法總結
參考部落格 傳送門 在上面的部落格中介紹了求序列第k大的幾種演算法,感覺收益良多,其中最精巧的還是利用快速排序的思想o n 查詢的演算法。仔細學習以後我將其中的幾個實現了一下。解法 1 將亂序陣列從大到小進行排序然後取出前k大,總的時間複雜度為o nlogn 解法 2 利用選擇排序或互動排序,取出前...
求區間第k大
int a mx void insert int a,int l,int r int divide int a,int l,int r 劃分子問題 a l x return l int select int s,int l,int r,int k,int len 返回s陣列l r的第k大數的下標 w...
陣列第K大
和第k小剛好相反 有乙個整數陣列,請你根據快速排序的思路,找出陣列中第k大的數。給定乙個整數陣列a,同時給定它的大小n和要找的k k在1到n之間 請返回第k大的數,保證答案存在。測試樣例 1,3,5,2,2 5,3 返回 2 先排序 快排 二分 第k大,則說明是第n k 1小 目的下標為n k 根據...