2321: 查找第k大

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大的都弄到最右邊呢

  1. 將第一個元素作爲 key,a[s]=key, 然後把比 key 大的移到右邊, 比key小的移到左邊, 一遍跑完之後,a[i]=key 。類似一趟快速排序。
  2. 選擇數組的前部或後部再進行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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章