算法学习——递归实践

递归实践:求两个有序序列的中位数

完成日期:2017/9/26


实验内容

1. 实践题目

求两个有序序列的中位数

2. 问题描述

已知有两个等长的非降序序列S1, S2, 设计函数求S1与S2并集的中位数。
有序序列A0 ,A1 ,⋯,AN−1 的中位数指A(N−1)/2 的值,即第⌊(N+1)/2⌋个数(A0 为第1个数)。
要求时间复杂度为o(logN)

3. 算法描述

分别求出序列a和序列b的中位数a[mid1]和b[mid2],比较两个中位数的大小,会出现三种情况:
1). a[mid1] = b[mid2]:即a[mid1]为两个序列的中位数;
2). a[mid1] < b[mid2]:则中位数会出在a[mid1]和b[mid2]之间,在序列a
中删除a[mid1]之前的元素得到序列a1,在序列b中删除b[mid2]之后的元素得到序列b1;
3). a[mid1] > b[mid2]: 则中位数会出在b[mid2]和a[mid1]之间,在序列a
中删除a[mid1]之后的元素得到序列a1,在序列b中删除b[mid2]之前的元素得到序列b1;
在a1和b1中分别求出中位数,重复上述步骤1 2 3,如果得到两个序列都只剩一个元素,则两个元素中较小的那个就是所求。
注意:因为要求每次两个序列要舍弃的长度要相等,因此序列有奇数个元素和偶数个元素要分开讨论。

4. 算法时间及空间复杂度分析

因为每次求得两个序列的中位数之后,得到的两个子序列的长度都是上两个序列的一半,因为循环共执行log2N次,因此时间复杂度为o(logN)。
因为算法除了简单的变量以外,没有与N规模相关的辅助变量,因此空间复杂度为o(1)。

5. 程序代码
#include <iostream>
using namespace std; 

void searchZ(int a[], int b[], int k){
    int l1 =0, l2 = 0, r1 = k-1, r2 = k-1;
    int mid1, mid2;
    while (l1 <r1&&l2 <r2){
        mid1 = (l1 + r1) / 2;
        mid2 = (l2 + r2) / 2;
        if ( a[mid1] == b[mid2]){
            cout << a[mid1] << endl;
            return;
        }
        else if (a[mid1] < b[mid2]){

            if((l1 + r1) % 2 == 0){
                l1 = mid1;
                r2 = mid2;
            }
            else{
                l1 = mid1 + 1;
                r2 = mid2;
            }
        }
        else{

            if((l1 + r1) % 2 == 0){

                r1 = mid1;
                l2 = mid2;
            }
            else{
                r1 = mid1;
                l2 = mid2 + 1;
            }
        }   
    }
    if (a[l1] < b[l2]){
        cout << a[l1];
    }
    else{
        cout << b[l2];
    }
    return;
} 

int main() {

    int k;
    cin >> k;
    int n[k+1];
    int m[k+1];
    for (int i = 0; i <k; i++){
        cin >> n[i];
    }
    for (int j = 0; j < k; j++){
        cin >> m[j];
    }
    searchZ(m, n, k);
    return 0;
}
6. 程序运行截图

这里写图片描述

7. 心得体会

看到题目所要求的时间复杂度为o(logn)时,结合之前所学的归并排序,知道如果要算法时间的数量级为logn的话,每循环一次之后数据的规模都要减半,因此首先需要思考如何在每一次循环之后n要变成n/2,也就是运用上mid。
然后算法的框架出来之后,一开始运行的时候出现了无限循环的情况,后来思考了一下,发现自己忽略两个序列每次都要舍弃的长度要相同,因此需要分奇偶讨论。
后来老师提出了一个不需要分奇偶讨论的方法,就是mid1 = (left1 + right1) /2, mid2 = (left2 + right2+1)/2,这样对奇数个元素时没有影响,但是又能保证在偶数个元素时,两个序列舍弃的长度相同,但是这种做法我在实施的时候,遇到了一个很严重的问题:

这里写图片描述

思考了很久只得出了一个解决方法= =,就是在最后每个序列只剩下2个元素的时候,对这四个元素进行排序得到中位数,这样对时间复杂度没有做什么贡献,但是会有些累赘。除了这个以外就没想到其他的方法了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值