emmm没做出来,太菜了我。换个封面。
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。你可以假设 nums1 和 nums2 不会同时为空。
示例 1:
nums1 = [1, 3]
nums2 = [2]
则中位数是 2.0
示例 2:
nums1 = [1, 2]
nums2 = [3, 4]
则中位数是 (2 + 3)/2 = 2.5
合并有序数组自然可以,但是复杂度就超了。看到这个复杂度要求,想到的是二分。然后就没了。接着就哀嚎自己菜啊。
下面是搬运解题思路大佬的
其实二分思想就是从数组的两边夹逼或排除,由循环不变式可知循环返回的那个位置就是满足查找条件(比如插入的位置)的位置。
a数组长度为n,b数组长度为m;
首先,找a和b两个有序数组中第K小,就是在a中找某个位置i,在b中找某个位置j,其满足条件为:
1、i+j=k
2、a[i-1]<=b[j]&&b[j-1]<=a[i]
这样第K小即为:max(a[i-1],b[j-1]);
其次,我们就可以在a数组中二分查找位置i,相应b中位置j=k-i,但是要注意b中j的位置不能越过b的边界即:0<=j<=m,
这样可以得到在a数组中二分查找的范围:0<=i<=n且k-m<=i<=k即max(0,k-m)<=i<=min(k,n);
我们可以在这个范围内用二分模板查找i的位置。
最后,二分找到i即代码中的le后,注意边界判断如果位置i和j前面都有元素,第k小=max(a[i-1],b[j-1]);如果i=0,
第k小=b[j-1];如果j=0;第k小=a[i-1];
两个有序数组的中位数即为:1、两个数组长度(m+n)为奇数,求第(m+n)/2+1小元素;2、两个数组长度(m+n)为偶数,求
第(m+n)/2小、第(m+n)/2+1小,两者平均值。
作者:nojoker
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/jiang-qi-zhuan-wei-zhao-liang-ge-you-xu-shu-zu-de-/
C艹代码:
class Solution {
public:
int findKthElm(vector
& nums1,vector & nums2,int k){ assert(1<=k&&k<=nums1.size()+nums2.size());
int le=max(0,int(k-nums2.size())),ri=min(k,int(nums1.size()));
while(le
int m=le+(ri-le)/2;
if(nums2[k-m-1]>nums1[m]) le=m+1;
else ri=m;
}//循环结束时的位置le即为所求位置,第k小即为max(nums1[le-1]),nums2[k-le-1]),但是由于le可以为0、k,所以
//le-1或者k-le-1可能不存在所以下面单独判断下
int nums1LeftMax=le==0?INT_MIN:nums1[le-1];
int nums2LeftMax=le==k?INT_MIN:nums2[k-le-1];
return max(nums1LeftMax,nums2LeftMax);
}
double findMedianSortedArrays(vector
& nums1, vector & nums2) { int n=nums1.size()+nums2.size();
if(n&1){//两个数组长度和为奇数
return findKthElm(nums1,nums2,(n>>1)+1);
}
else{//为偶数
return (findKthElm(nums1,nums2,n>>1)+findKthElm(nums1,nums2,(n>>1)+1))/2.0;
}
}
};
照例贴上巨佬代码:
class Solution {
public:
double findMedianSortedArrays(vector
& nums1, vector & nums2) {
int len1=nums1.size();
int len2=nums2.size();
int k1=(len1+len2+1)/2;
int k2=(len1+len2+2)/2;
return (findK(nums1,nums2,0,len1-1,0,len2-1,k1)+findK(nums1,nums2,0,len1-1,0,len2-1,k2))/2;
}
double findK(vector
& nums1, vector & nums2,int left1,int right1,int left2,int right2,int k) {
int len1=right1-left1+1;
int len2=right2-left2+1;
if(len1>len2) return findK(nums2,nums1,left2,right2,left1,right1,k);
if(len1==0) return nums2[left2+k-1];
if(k==1) return min(nums1[left1],nums2[left2]);
int pos1=left1+min(len1,k/2)-1;
int pos2=left2+min(len2,k/2)-1;
if(nums1[pos1]>nums2[pos2])
{
return findK(nums1,nums2,left1,right1,pos2+1,right2,k-(pos2-left2+1));
}
else
{
return findK(nums1,nums2,pos1+1,right1,left2,right2,k-(pos1-left1+1));
}
}
};