两个非等长有序序列的中位数

问题:查找两个非等长有序序列的中位数(要求时间复杂度为logn)

#include <cstdio>

const int sizeN = 1<<20;
const int sizeM = 2500001;
int a[sizeM];
int b[sizeM];

int median(int *a,int *b, int n1,int n2,int lowa,int lowb);

int main()
{
    int n1,n2;
    scanf("%d",&n1);
    for ( int i = 0 ; i<n1; ++i)
    {
        scanf("%d",&a[i]);
    }
    scanf("%d",&n2);
    for ( int i = 0 ; i<n2; ++i)
    {
        scanf("%d",&b[i]);
    }
    for (int i=0;i<100000; ++i) /*调用100000次放大执行时间*/     
    {
        median(a,b,n1,n2,0,0);
    }
    printf("%d\n",median(a,b,n1,n2,0,0));
    return 0;
}

/* 请在这里填写答案 */

函数接口:

int median(int *a,int *b, int n1,int n2,int lowa,int lowb);


其中 a 和 b 分别是两个数组序列的首地址。 n1,n2则是对应的数组元素的数目。lowa,lowb分别为两个数组的首元素下标。即序列区间分别为[lowa,lowa+n1)与[lowb,lowb+n2)。函数返回a数组区间[lowa,lowa+n1)与b数组区间[lowb,lowb+n2) 的元素合并为一个序列的中位数。一个有n个数的有序序列的中位数是第⌊(n+1)/2⌋个数,即低位中位数。

裁判测试程序样例:
在这里给出一组输入。例如
4
1 2 3 4
6
5 6 7 8 9 10

输出样例:
5

基于Monster 组和GPT的调写:

img


完整的 median 函数代码

int median(int *a, int *b, int n1, int n2, int lowa, int lowb) {
    if (n1 > n2) {
        return median(b, a, n2, n1, lowb, lowa); // 保证 n1 <= n2
    }
    if (n1 == 0) {
        return b[lowb + (n2-1)/2]; // a 为空数组
    }
    int left = 0, right = n1;
    while (left <= right) {
        int mid = (left + right) / 2;
        int j = (n1 + n2 + 1) / 2 - mid; // j 为 b 中的下标
        if (j > 0 && mid < n1 && b[lowb+j-1] > a[lowa+mid]) {
            left = mid + 1; // mid 太小,需要右移
        } else if (mid > 0 && j < n2 && a[lowa+mid-1] > b[lowb+j]) {
            right = mid - 1; // mid 太大,需要左移
        } else { // mid 正好是中位数
            if (mid == 0) {
                return b[lowb+j-1];
            } else if (j == 0) {
                return a[lowa+mid-1];
            } else {
                return std::max(a[lowa+mid-1], b[lowb+j-1]);
            }
        }
    }
    // 不应该执行到这里
    return -1;
}

主函数和median 函数代码



#include <cstdio>
#include <algorithm>

const int sizeN = 1<<20;
const int sizeM = 2500001;
int a[sizeM];
int b[sizeM];

int median(int *a, int *b, int n1, int n2, int lowa, int lowb) {
    if (n1 > n2) {
        return median(b, a, n2, n1, lowb, lowa); // 保证 n1 <= n2
    }
    if (n1 == 0) {
        return b[lowb + (n2-1)/2]; // a 为空数组
    }
    int left = 0, right = n1;
    while (left <= right) {
        int mid = (left + right) / 2;
        int j = (n1 + n2 + 1) / 2 - mid; // j 为 b 中的下标
        if (j > 0 && mid < n1 && b[lowb+j-1] > a[lowa+mid]) {
            left = mid + 1; // mid 太小,需要右移
        } else if (mid > 0 && j < n2 && a[lowa+mid-1] > b[lowb+j]) {
            right = mid - 1; // mid 太大,需要左移
        } else { // mid 正好是中位数
            if (mid == 0) {
                return b[lowb+j-1];
            } else if (j == 0) {
                return a[lowa+mid-1];
            } else {
                return std::max(a[lowa+mid-1], b[lowb+j-1]);
            }
        }
    }
    // 不应该执行到这里
    return -1;
}


int main()
{
    int n1,n2;
    scanf("%d",&n1);
    for ( int i = 0 ; i<n1; ++i)
    {
        scanf("%d",&a[i]);
    }
    scanf("%d",&n2);
    for ( int i = 0 ; i<n2; ++i)
    {
        scanf("%d",&b[i]);
    }
    for (int i=0;i<100000; ++i) { //调用100000次放大执行时间
        median(a,b,n1,n2,0,0);
    }
    printf("%d\n",median(a,b,n1,n2,0,0));
    return 0;
}

该回答通过自己思路及引用到GPTᴼᴾᴱᴺᴬᴵ搜索,得到内容具体如下:
这个问题可以使用分治法来解决,时间复杂度为 O(log(n1+n2))。

具体思路如下:

  1. 找到两个序列的中位数,分别为 m1 和 m2,如果 m1 == m2,直接返回 m1 或 m2。

  2. 如果 m1 < m2,则舍弃 a 数组中的前半部分和 b 数组中的后半部分,继续在 a 数组的后半部分和 b 数组的前半部分中寻找中位数。

  3. 如果 m1 > m2,则舍弃 a 数组中的后半部分和 b 数组中的前半部分,继续在 a 数组的前半部分和 b 数组的后半部分中寻找中位数。

  4. 重复执行步骤 1~3,直到找到两个序列的中位数为止。

代码如下:

#include <cstdio>
#include <algorithm>

const int sizeN = 1<<20;
const int sizeM = 2500001;
int a[sizeM];
int b[sizeM];

int median(int *a,int *b, int n1,int n2,int lowa,int lowb)
{
    if (n1 == 0) {
        return b[lowb + (n2-1)/2];
    }
    if (n2 == 0) {
        return a[lowa + (n1-1)/2];
    }
    if (n1 == 1 && n2 == 1) {
        return std::min(a[lowa], b[lowb]);
    }
    int m1 = a[lowa + (n1-1)/2];
    int m2 = b[lowb + (n2-1)/2];
    if (m1 == m2) {
        return m1;
    }
    if (m1 < m2) {
        return median(a, b, n1-(n1-1)/2, n2/2, lowa+(n1-1)/2, lowb);
    } else {
        return median(a, b, n1/2, n2-(n2-1)/2, lowa, lowb+(n2-1)/2);
    }
}

int main()
{
    int n1,n2;
    scanf("%d",&n1);
    for ( int i = 0 ; i<n1; ++i)
    {
        scanf("%d",&a[i]);
    }
    scanf("%d",&n2);
    for ( int i = 0 ; i<n2; ++i)
    {
        scanf("%d",&b[i]);
    }
    printf("%d\n",median(a,b,n1,n2,0,0));
    return 0;
}

如果以上回答对您有所帮助,点击一下采纳该答案~谢谢