题目:
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n))
示例1:
输入:nums1 = [1,3], nums2 = [2] 输出:2.00000 解释:合并数组 = [1,2,3] ,中位数 2示例2:
输入:nums1 = [0,0], nums2 = [0,0] 输出:0.00000来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays
思路:
这道题本身要做出来并不难,直接用两个指针加一个新数组就可以找到中位数。但是有一个关键点不能满足,就是时间复杂度,上述T(n)是O(m+n),而题目要求O(log(m+n)),苦思无果,还是看到一个题解,思想真的神奇。
回归看这道题的本意,中位数,那中位数实际上是什么意思呢?其实是把一组数分成两个相同的部分,左边一定全部小于右边。换言之,当你把一组数分成这两个部分,找到的这个切分点其实就是中位数(偶数自然取两边边缘除2)。对于本题两个有序数组而言,我们实际上要找的是每一个数组的切分点,使得第一个数组的左边一定小于第二个数组的右边,第一个数组的右边也一定大于第二个数组的左边,这个找到的两个切分点再进行操作即可获得两个数组的中位数。比如:
[2 3 | 5]
[1 4 | 7 9]
整体思想是这样,但是会发现实现起来并不容易,这时一个神奇的操作出现了。把所有数组的每一个数加一个#,使之长度一定成为偶数,这样切分的时候在‘#’
上等于割在2个元素之间,在数字上等于把数字划到2个部分。还要注意,这一步只是思想上这样,真实实现的时候并不会真正给数组加‘#’。
除此以外,还有特殊情况,就是两个数组中一个数组完全大于或完全小于中位数,这样就有四种特殊情况,要作单独处理。
最后,在查找两个切分点的时候使用二分,这样log的复杂度不就有了吗?
代码:
#include <iostream>
#include <vector>
using namespace std;
class Solution
{
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2)
{
int n=nums1.size();
int m=nums2.size();
//整体思想实际上是找到两个数组的某个点进行分割,使得这两个点(中位数)能将左右分开
//保证数组1最短
if(n>m)
return findMedianSortedArrays(nums2,nums1);
//Lmaxi代表第i个数组截取后左边的元素,Rmini代表第i个数组截取后右边的元素
int Lmax1,Lmax2,Rmin1,Rmin2;
//ci代表数组i截取的位置
int c1,c2;
//对数组1作二分用到的指针,虚拟加了'#'所以数组1是2*n长度
int low=0,high=2*n;
while(low<=high)
{
c1=(low+high)/2;
c2=n+m-c1;
//四种特殊情况的处理
//比如第一行:数组1整体都在右边了,所以都比中值大,中值在数组2中,简单的说就是数组1割后的左边是空了,所以我们可以假定LMax1 = INT_MIN
Lmax1 = (c1 == 0) ? INT_MIN : nums1[(c1 - 1) / 2];
Rmin1 = (c1 == 2 * n) ? INT_MAX : nums1[c1 / 2];
Lmax2 = (c2 == 0) ? INT_MIN : nums2[(c2 - 1) / 2];
Rmin2 = (c2 == 2 * m) ? INT_MAX : nums2[c2 / 2];
//找到Lmax1<Rmin2并且Lmax2<Rmin1的两个点
if(Lmax1>Rmin2){
high=c1-1;
}else if(Lmax2>Rmin1){
low=c1+1;
}else
break;
}
return (max(Lmax1,Lmax2)+min(Rmin1,Rmin2))/2.0;
}
};
int main()
{
int m,n,e;
cin>>m>>n;
vector<int> nums1,nums2;
for(int i=0; i<m; i++)
{
cin>>e;
nums1.push_back(e);
}
for(int i=0; i<n; i++)
{
cin>>e;
nums2.push_back(e);
}
double res;
res=Solution().findMedianSortedArrays(nums1,nums2);
cout<<res;
return 0;
}