求 n + 2 个数的平均数

题目描述

给定一个按非递减排序的正整数数组𝐴[1,2, … , 𝑛],以及两个正整数 𝑥 和 𝑦,请设计算法求这 𝑛 + 2 数的中位数。这里的中位数定义为 𝑛 + 2 为奇数时,中位数为最中间大小的那个数, 𝑛 + 2 为偶数时,中位数为最中间大小的两个数的均值,并分析算法的时间代价。

问题分析

两个正整数,可以将较小的数记为 x,较大的数记为 y,方便后续的处理。

可以先分别查找原始数组中,不小于 x、不小于 y 的数的下标,分别记为 px 和 py。

若数组个数为奇数,即中位数是中间的那个数,将原数组中中位数的下标记为 idx:

  • px <= idx && py >= idx:中位数不变,仍是a[idx]
  • py < idx:中位数可能是ya[idx-1],取二者最大值。
  • px > idx:中位数可能是xa[idx+1],取二者最小值。

若数组个数为偶数,即中位数是最中间的两个数的均值,将这两个数的下标分别记为 idx - 1 和 idx:

  • px <= idx-1 && py >= idx:中位数为(a[idx-1] + a[idx]) / 2.0
  • py <= idx-1:中位数为(max(y, a[idx-2])+ a[idx-1]) / 2.0
  • px >= idx:中位数为(a[idx] + min(x, a[idx+1])) / 2.0

复杂度分析

时间开销主要在两次二分查找,为 O ( l o g n ) O(logn) O(logn)

程序代码

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

// O(logn)
// 找到数组中大于等于num的第一个位置
int binarySearch(const vector<int>& a, int num)
{
    int l = 0, r = a.size();
    while(l < r) {
        int mid = (l + r) >> 1;
        if(a[mid] < num) {
            l = mid + 1;
        }
        else {
            r = mid;
        }
    }
    return l;
}

int main()
{
    int n;
    cin >> n;
    vector<int> a(n);
    for(int i = 0; i < n; i++) {
        cin >> a[i];
    }
    int x, y;
    cin >> x >> y;
    
    // 小的数作为x
    if(x > y)  swap(x, y);
    
    int px = binarySearch(a, x), py = binarySearch(a, y);

    // 中位数位置初始值
    int idx = n >> 1;
    double res;
    if( n & 1 ) {
        if(px <= idx && py >= idx) {
            res = a[idx];
        }
        else if( py < idx ) {
            res = max(y, a[idx-1]);
        }
        else {
            res = min(x, a[idx+1]);
        }
    }
    else {
        if(px <= idx-1 && py >= idx) {
            res = (a[idx-1] + a[idx]) / 2.0;
        }
        else if( py <= idx-1 ) {
            res = (max(y, a[idx-2])+ a[idx-1]) / 2.0;
        }
        else {
            res = (a[idx] + min(x, a[idx+1])) / 2.0;
        }
    }
    
    cout << res << endl;
    
    return 0;
}
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值