Median of Two Sorted Arrays

leetCodebook 2.1.5 Median of Two Sorted Arrays

题目描述:

There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted
arrays. The overall run time complexity should be O(log(m + n)).
Example 1:

nums1 = [1, 3]
nums2 = [2]

The median is 2.0
Example 2:

nums1 = [1, 2]
nums2 = [3, 4]

The median is (2 + 3)/2 = 2.5

题目分析:

两个有序数列 A,B求他们的中位数。时间复杂度要求为O(log(m+n))
median:中位数 ,如果数列有偶数个数,那么中位数为中间两个数的平均值;如果数列有奇数个数,那么中位数为中间的那个数。

解题思路:

这个题更通用的形式是求第k大的元素

1.采用归并排序的思想把两个数组进行合并,取第k大的元素。时间复杂度为O(nlogn) 这个是怎么的出来的?
2.O(n) 使用一个计数器m,记录已找到第m大元素,pA,pB分别指向数组A,B。pA小于pB,pA++,m++,反之pB++,m++,直到m==k 输出。
3.O(logn) 采用类似二分查找的方法,每次删除第k大元素之前的一个元素需要K次,若每次都删除一半(k/2)。
算法导论中对order statistic问题进行过讨论,因此,在有序又要求log级的时间复杂度,可以考虑分治策略,采用二分法。
每次取A,B 的 k/2的元素进行比较 以A为例有以下几种情况,必然有其中一部分是可以舍弃的
1. A不够k/2个元素,舍弃 B k/2 之前的数据
2. A[k/2] < B[k/2] ,舍弃 A k/2 之前的数据
3. A[k/2] == B[k/2],返回 A[k/2] 或者 B[k/2]

我们可以写一个递归函数 函数的返回条件
1、A[k/2-1] == B[k/2-1]
2、k==1,min(A[0],B[0])
3、A或者B为空 A[k]或B[k]

证明:
a、使用反证法(k为偶数)证明第一种情况
假设k值在B中的索引为 m( m<=k/21 m <= k / 2 − 1 ), A的数量 k-(m+1), 又An < k/2
m<=k/21=>m+1<=k/2k(m+1)>=k/2 m <= k / 2 − 1 => m + 1 <= k / 2 则 k − ( m + 1 ) >= k / 2 矛盾 所以 k值一定不再B[0~k/2-1] 中成立

b、使用反证法(k为偶数)
假设 k在A[0~k/2-1]中的位置为 m(m<=k/2-1) 那么 B中必然有 k-(m+1) 之前的元素
m<=k/2-1
=> m+1 <= k/2
k-(m+1) >= k/2 //B[k/2-1] 在{0~k-(m+1)}内
=>B[k/2-1] <=A[m]
A[k/2-1] >= A[m] => A[k/2-1] >= B[k/2-1] 与题设矛盾

代码实现:

#include <vector>
#include <algorithm>
using std::vector;
using std::min;
using std::max;

int a_arr[] = {1,3,4,5};
int cout_a = sizeof(a_arr)/sizeof(int);
vector<int> arrA(a_arr,a_arr+cout_a);
int b_arr[] = {2,6,7,8,9};
int cout_b = sizeof(b_arr)/sizeof(int);
vector<int> arrB(b_arr,b_arr+cout_b);

//index_1 已排除元素的个数
int findKthNumber(vector<int> &num_1,int index_1,vector<int>&num_2,int index_2,int k)
{
    int len_1 = num_1.size() - index_1;
    int len_2 = num_2.size() - index_2;

    //k取值范围 0~total 由调用者判断
    //确保 num_1 是较长的一个
    if (len_1<len_2)
        return findKthNumber(num_2,index_2,num_1,index_1,k);

    //num_2 空 返回 num_1
    if (0==len_2)
        return num_1[k-1];
    if (1 == k)
        return min(num_1[index_1],num_2[index_2]);

    int cut_2 = min(len_2,k/2);
    int cut_1 = k - cut_2;
    if ( num_1[index_1+cut_1-1] < num_2[index_2+cut_2-1] )
        return findKthNumber(num_1,index_1+cut_1,num_2,index_2,k-cut_1);

    else if( num_1[index_1+cut_1-1] > num_2[index_2+cut_2-1] )
        return findKthNumber(num_1,index_1,num_2,index_2+cut_2,k-cut_2);

    else
        return num_1[index_1+cut_1-1];

}

double findMedianSortedArr(vector<int>&num_1,vector<int>&num_2)
{
    int total = num_1.size() + num_2.size();
    //判断奇数还是偶数
    if (total & 0x01)
    {
        //奇数
        return findKthNumber(num_1,0,num_2,0,total/2+1);
    }
    else
    {
        return ( findKthNumber(num_1,0,num_2,0,total/2)
            + findKthNumber(num_1,0,num_2,0,total/2+1))/2.0;
    }

}

参考
https://zhuanlan.zhihu.com/p/27104702?refer=linjichu
http://www.cnblogs.com/yuzhangcmu/p/4138184.html
https://www.jianshu.com/p/9bd57fd52062
《leetCode Book》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值