PTA:两个有序序列的中位数(二分法)

两个有序序列的中位数

题目:
PTA:两个有序序列的中位数(二分法)_第1张图片

代码如下:

#include
using namespace std;
int searchMid(int a[],int b[],int n) {
    int low1 = 0, low2 = 0, high1 = n - 1, high2 = n - 1;
    while (low1 < high1&&low2 < high2) {
        int mid1 = (low1 + high1) / 2;
        int mid2 = (low2 + high2) / 2;
        if (a[mid1] == b[mid2]) {
            return a[mid1];
        };
        if (a[mid1] < b[mid2]) {
            if ((low1 + high1) % 2 == 0) {
                low1 = mid1;
                high2 = mid2;
            }
            else {
                low1 = mid1 + 1;
                high2 = mid2 ;
            }
        }
        else {
            if ((low1 + high1) % 2 == 0) {
                high1 = mid1;
                low2 = mid2;
            }
            else {
            //加1,保证取得的数列长度一样
                high1 = mid1;
                low2 = mid2 +1;
            }
        }
    };
    if (a[low1] < b[low2]) {
        cout << a[low1] << endl;
    }
    else {
        cout << b[low2] << endl;
    }
}
int main() {
    int a[100000];
    int b[100000];
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }
    for (int i = 0; i < n; i++) {
        cin >> b[i];
    }
    searchMid(a, b, n);
    system("pause");
    return 0;
}

解析:
这道题如果使用排序方法再求中位数,时间复杂度就会超过O(logn)(排序算法最低时间复杂度为nlogn),不满足题意。于是使用二分搜索的算法,分别比较两个数列的中位数。

  1. 当a[mid]和b[mid]相等时,中位数即为该数,直接返回;
  2. 当a[mid]大于b[mid]时,中位数一定在a[mid]前的数列或b[mid]后的数列中,此时我们只取这两部分,继续进行二分比较。
  3. 当a[mid]小于b[mid]是,中位数一定在a[mid]后的数列或b[mid]前的数列中,此时我们只取这两部分,继续进行二分比较。

Q:为什么这样划分数列(分别取前半段和后半段)?
A:因为要让剩下的数列的中位数相接近,这样就可以直接返回总的中位数。

当退出循环条件之后,直接比较两数中位数,小的那个就是最后的结果。
PTA:两个有序序列的中位数(二分法)_第2张图片
PTA:两个有序序列的中位数(二分法)_第3张图片
PTA:两个有序序列的中位数(二分法)_第4张图片
PTA:两个有序序列的中位数(二分法)_第5张图片

此时只剩下最后一个数,因为mid向下取整,所以较小的即为全局的中位数。

复杂度分析

时间复杂度:
因为采用二分查找算法来寻找中位数而不是排序,所以时间复杂度为O(logn)。
空间复杂度:
运行过程中并没有开辟额外的空间,所以空间复杂度为O(1)。


参考资料:
https://blog.csdn.net/gdufsTFknight/article/details/78824552
https://blog.csdn.net/Scar_Halo/article/details/83691880

你可能感兴趣的:(算法)