65. 两个排序数组的中位数
中文English
两个排序的数组A和B分别含有m和n个数,找到两个排序数组的中位数,要求时间复杂度应为O(log (m+n))。
样例
样例1
输入:
A = [1,2,3,4,5,6]
B = [2,3,4,5]
输出: 3.5
样例2
输入:
A = [1,2,3]
B = [4,5]
输出: 3
挑战
时间复杂度为O(log n)
算法1:最简单的办法就是把两个数组合并、排序,然后返回中位数即可,由于两个数组原本是有序的,因此可以用归并排序中的merge步骤合并两个数组。算法复杂度为O(m+n)
class Solution {
public:
double findMedianSortedArrays(vector<int> &A, vector<int> &B) {
// write your code here
vector<int> C;
int i=0,j=0,m=A.size(),n=B.size();
while(i<m&&j<n)
{
if(A[i]<=B[j])
{
C.push_back(A[i]);
i++;
}
else
{
C.push_back(B[j]);
j++;
}
}
while(i<m)
{
C.push_back(A[i]);
i++;
}
while(j<n)
{
C.push_back(B[j]);
j++;
}
int k=C.size();
if(k%2==0)
{
return (C[k/2]+C[k/2-1])/2.0;
}
else
{
return C[(k-1)/2];
}
}
};
算法2:对于一个长度为n的已排序数列a,若n为奇数,中位数为第(n/2+1)个数 , 若n为偶数,则中位数=[第(n/2)个数 + 第(n/2+1)个数] / 2 如果我们可以在两个数列中求出第K小的元素,便可以解决该问题
不妨设数列A元素个数为n,数列B元素个数为m,各自升序排序,求第k小元素
取A[k / 2] B[k / 2] 比较, 如果 A[k / 2] > B[k / 2] 那么,所求的元素必然不在B的前k / 2个元素中(证明反证法) 反之,必然不在A的前k / 2个元素中,于是我们可以将A或B数列的前k / 2元素删去,求剩下两个数列的 k - k / 2小元素,于是得到了数据规模变小的同类问题,递归解决
如果 k / 2 大于某数列个数,所求元素必然不在另一数列的前k / 2个元素中,同上操作就好。
class Solution {
public:
double findKth(vector<int> &A, vector<int> &B, int A_st, int B_st, int k)
{
// 首先需要让数组1的长度小于或等于数组2的长度
if (A.size() - A_st > B.size() - B_st)
{
return findKth(B, A, B_st, A_st, k);
}
// 判断小的数组是否为空,为空的话,直接在另一个数组找第K个即可
if (A.size() == A_st)
{
return B[B_st + k - 1];
}
// 当K = 1时,表示我们要找第一个元素,只要比较两个数组的第一个元素,返回较小的那个即可
if (k == 1) {
return min(A[A_st], B[B_st]);
}
int pa = min(A_st + k / 2, int(A.size())), pb = B_st + k - (pa -A_st);
if (A[pa - 1] < B[pb - 1]) {
return findKth(A, B, pa,B_st, k - pa + A_st);
}
else if (A[pa - 1] > B[pb - 1]) {
return findKth(A, B, A_st, pb, k - pb + B_st);
}
else {
return A[pa - 1];
}
}
double findMedianSortedArrays(vector<int> &A, vector<int> &B) {
// write your code here
int sum = A.size() + B.size();
double ret;
if (sum %2!=0)
{
ret = findKth(A, B, 0, 0, sum / 2 + 1);
}
else
{
ret = ((findKth(A, B, 0, 0, sum / 2)) +
findKth(A, B, 0, 0, sum / 2 + 1)) / 2.0;
}
return ret;
}
};