[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;
}
原文地址:https://www.cnblogs.com/kbyd/p/3037694.html