POJ3579 Median(二分答案 + O(N)判定)

高效求解中位数
本文介绍了一种针对大规模数据集高效求解两数之差序列中位数的方法。通过数组排序及双指针技巧实现了O(N)的时间复杂度,避免了直接计算所有差值的耗时操作。

出处:http://blog.youkuaiyun.com/gengmingrui/article/details/47671265

传送门 

大意:给出 N 个数,对于存有每两个数的差值的序列求中位数,如果这个序列有偶数个元素,就取中间偏小的作为中位数。

因为 N<=100000 ,所以想要求出每一个差值是不可行的,我们很容易想到二分答案。 在二分答案时我们会进行判定,求出小于等于枚举值的个数,我看其他人的判定似乎都是 O(NlogN)  的,我在这里就给出一个 O(N) 的判定方法。

首先同样将数组排序(我们命名为a数组好了) 
我们枚举一个区间 [l,r) ,因为当r增加的时候,要使 [l,r) 中的数都大于于等于 a[r] lrl,O(n)

上代码:

#include <cstdio>
#include <algorithm>
long long n, a[100005];
int main()
{
    long long i, j;
    while(~scanf("%I64d", &n))
    {
        for(i = 1; i <= n; i ++)
            scanf("%I64d", a + i);
        std::sort(a + 1, a + n + 1);
        long long l = 0, r = a[n], mid, m = (n-1)*n/4, num;
        if((n*(n-1)/2)&1) m ++;
        if(n == 1)
        {
            printf("0\n");
            continue;
        }
        while(l < r)
        {
            mid = (l + r) >> 1;
            j = 1;
            num = 0;
            for(i = 2; i <= n; i ++)
            {
                while(a[i] - a[j] > mid)
                    j ++;
                num += (i-j);
            }
            if(num >= m)
                r = mid;
            else l = mid + 1;
        }
        printf("%I64d\n", l);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值