[HDU] 1157 Who's in the Middle - 不排序查找第x小的元素,时间复杂度接近o(n)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1157
方法:通过像快速排序那样进行一个划分,划分只对一个部分进行处理而不是像快速排序那样对两个都处理。当随机选择一个元素进行了划分后,开划分的位子k在哪里,如果把x-th元素的x等于k,则直接返回,小于,就在前面一个部分递归下去找地x-th小的元素, 否则,x-=k,在后面一个部分去找。在该题目中x为n/2+1.
感谢:时间复杂度接近o(n),这是根据概率分布计算出来的,以后要学会其证明,包括快速排序的证明。
代码:
View Code
#include <iostream> #include <stdlib.h> #include <time.h> using namespace std; int n; int numbers[10001]; int getRandomNumber(int st,int ed) { srand((unsigned)time(NULL)); return (rand()%(ed-st+1))+st; } int partion(int st,int ed) { int i =st-1; int j=st; int r = ed; for(j=st;j<r;j++) { if(numbers[j]<=numbers[r]) { i++; int temp = numbers[j]; numbers[j] = numbers[i]; numbers[i] = temp; } } int temp = numbers[r]; numbers[r] = numbers[i+1]; numbers[i+1] = temp; return i+1; } int randonPartion(int st,int ed) { int p = getRandomNumber(st,ed); int temp = numbers[p]; numbers[p] = numbers[ed]; numbers[ed]=temp; return partion(st,ed); } int getTarget(int x,int st = 1,int ed=n) { int p= randonPartion(st,ed); int k = p-st+1; if(k==x) return numbers[st+k-1]; else { if(x>k) return getTarget(x-k,p+1,ed); else return getTarget(x,st,p-1); } } int main() { while(scanf("%d",&n)!=EOF) { for(int i = 1;i<=n;i++) scanf("%d",&numbers[i]); cout<<getTarget(n/2+1)<<endl; } return 0; }