GEEK编程练习— —两个已序数组的中值

题目

给定两个已经排序好的数组,找到两者的中值。

分析

首先把这个问题可以化成一般形式,寻找两个已序数组中所有元素的第k大元素。
1、最直接的解法,合并两个数组然后求第k大的元素。但是我们仅仅需要第k大的元素,不需要排序这么“昂贵”的操作。
2、可以用一个计数器,记录当前已经找到第m大的元素了。同时使用两个指针pA和pB,分别指向A和B数组的第一个元素,如数组A当前元素小,则pA++,同时m++;如数组B当前元素小,则pB++,同时m++;最终当m等于k时,得到答案。但是当k接近m+n时,与第一种解法复杂度相同。
3、假设A和B元素个数都大于k/2,将A的第k/2个元素和B的第k/2个元素比较,有三种情况(为了简化先假设k为偶数,结论对奇数也成立)
A[k/2-1] == B[k/2-1]
A[k/2-1] > B[k/2-1]
A[k/2-1] < B[k/2-1]
当A[k/2-1] < B[k/2-1]时,A[k/2-1]不大于A与B合并后的第k大元素。可以删除A数组的这k/2个元素。同理,A[k/2-1] > B[k/2-1]时,可以删除B数组的这k/2个元素。
当A[k/2-1] == B[k/2-1]时,说明找到了第k大的元素,直接返回A[k/2-1]或B[k/2-1]。

代码

//Date:2016-04-19
//Author:Sin_Geek
//时间负责度O(log(m+n)),空间复杂度O(log(m+n))

#include <vector>
#include <iostream>
#include <algorithm>

using namespace std;

int find_kth(vector<int>::const_iterator A, int m, vector<int>::const_iterator B, int n, int k)
{
    if (m > n)
        return find_kth(B, n, A, m, k);
    if (m == 0)
        return *(B + k - 1);
    if (k == 1)
        return min(*A, *B);

    int ia = min(k / 2, m), ib = k - ia;
    if (*(A + ia - 1) < *(B + ib - 1))
        return find_kth(A + ia, m - ia, B, n, k - ia);
    else if (*(A + ia - 1) > *(B + ib - 1))
        return find_kth(A, m, B + ib, n - ib, k - ib);
    else
        return A[ia - 1];
}

double findMedianSortedArrays(const vector<int>& A, const vector<int>& B)
{
    const int m = A.size();
    const int n = B.size();
    int total = m + n;
    if (total & 0x1) //奇偶判断
        return find_kth(A.begin(), m, B.begin(), n, total / 2 + 1);
    else
        return (find_kth(A.begin(), m, B.begin(), n, total / 2) + find_kth(A.begin(), m, B.begin(), n, total / 2 + 1)) / 2.0;
}
int main()
{
    vector<int> A = {1,2,3,5}, B = {2,4,5,6};
    cout << findMedianSortedArrays(A, B) << endl;

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值