Description
小W有很強的好勝心,也有很明確的目標,總是希望當第k名,但是小W太菜了,經常達不到目標,於是他每次考試後都想知道第k名的分數是多少,然後以它爲目標。 現在給出了每個人的分數,請求編程能力很強的你幫他迅速找到第k名的分數爲多少,這樣他纔有更多的時間去學習。
Input
第一行爲一個正整數t代表有t組數據(t<=10)。每組數據第一行爲兩個正整數n和k,第二行爲n個不超過109的正整數。 1 < =k < =n < =107
Output
對於每組數據,輸出第k大的數
Sample Input
1
6 2
1 2 3 4 5 6
Sample Output
5
解題思路
這題有個地方很坑,就是輸入數據量巨大,我的算法沒有問題,但是大量的時間用來輸入數據了,所以我交上去總是超時,後來百度才知道還有更快的讀入辦法,雖然我也不知道原理。但是這題我主要想說的不是這個讀入快慢問題,而是找第k大的數,常規思路是先排序然後就ok了, 複雜度nlogn,
我用的是類似快排的思想,引入一個操作arrangeRight(k, s, e)在數組 a[s,e] 中把前k大的放到最右邊。
如何將前k大的都弄到最右邊呢
- 將第一個元素作爲 key,a[s]=key, 然後把比 key 大的移到右邊, 比key小的移到左邊, 一遍跑完之後,a[i]=key 。類似一趟快速排序。
- 選擇數組的前部或後部再進行arrangeRight操作,這時前面有 f=i-s個元素,後面有r=e-i+1個元素。
如果 r=k 那麼 a[i] 就是我們要找的第k大的數;
如果 r<k 那麼到[s, i-1] 中找第k-r大的數,即arrangeRight(k-r, s, i-1)
如果 r>k 那麼到 [i+1, e] 中找第k大的數,即arrangeRight(k, i+1, e)
這樣的話O(n)的時間內就能找到第k大的數
AC Code
#include<iostream>
#include<set>
#include<cmath>
#include<stack>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define long long ll
namespace fastIO
{
#define BUF_SIZE 100000
bool IOerror = 0;
inline char nc()
{
static char buf[BUF_SIZE], *p1 = buf + BUF_SIZE, *pend = buf + BUF_SIZE;
if ( p1 == pend )
{
p1 = buf;
pend = buf + fread( buf, 1, BUF_SIZE, stdin );
if ( pend == p1 )
{
IOerror = 1;
return(-1);
}
}
return(*p1++);
}
inline bool blank( char ch )
{
return(ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t');
}
inline void rd( int &x )
{
char ch;
while ( blank( ch = nc() ) )
;
if ( IOerror )
return;
for ( x = ch - '0'; (ch = nc() ) >= '0' && ch <= '9'; x = x * 10 + ch - '0' )
;
}
#undef BUF_SIZE
};
using namespace fastIO;
using namespace std;
const int MAXN = 1e7 + 10;
int a[MAXN];
void arrangeRight(int k, int s, int e){ //[s,e]
int key=a[s], i=s, j=e;
while(i!=j){
while(j>i&&a[j]>=key) --j;
swap(a[i],a[j]);
while(i<j&&a[i]<=key) ++i;
swap(a[i],a[j]);
}//處理完後 a[i]=key
int r=e-i+1 , f=i-s;
if(r==k) return ;
else if(r>k) arrangeRight(k,i+1,e);
else arrangeRight(k-r,s,i-1);
}
int main(){
freopen("C:\\Users\\Ambition\\Desktop\\in.txt","r",stdin);
int aa, t, n, k;
// scanf("%d", &t);
rd(t);
while(t--){
// scanf("%d %d",&n,&k);
rd(n); rd(k);
for(int i=0; i<n; ++i){
// scanf("%d", &a[i]);
rd(a[i]);
}
arrangeRight(k, 0, n-1);
printf("%d\n", a[n-k]);
}
return 0;
}