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/2−1
m
<=
k
/
2
−
1
), A的数量 k-(m+1), 又An < k/2
m<=k/2−1=>m+1<=k/2则k−(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》