题目
There are two sorted arrays nums1 and nums2 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)).
You may assume nums1 and nums2 cannot be both empty.
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
分析
嗯这是一道算法导论的课后题。原来的课后题是找出两个有序数组中的第k小元素,这里的k变成中位数。在求中位数的时候有一个小技巧,可以涵盖奇数与偶数的情况。这里两个有序数组的长度分别为m和n,那么就是从m+n个数据中求中位数。那么这个中位数就是第(m+n+1)/2个数和第(m+n+2)/2个数的平均值。这个表达式包含奇数和偶数的情况。然后接下来的问题就转化为求两个有序数组的第(m+n+1)/2小元素和第(m+n+2)/2小元素。
两个有序数组数组求第k小数据,复杂度O(log(m+n)),肯定是要用到二分的。这里的二分的方式为:分别求两个数组的第k/2小元素,假如数组1的第k/2小元素小于数组2的第k/2小元素,那么数组1的前k/2个数据中不可能包含我们想要的第k小数据。然后讲数组1的前k/2个数据删除,求剩下的两个数组的第k-k/2小元素就好了。那么从剩下数组中选取第k-k/2小的元素,可以递归前面的方法。
简单来讲,两个数组假如合并成了一个,从前k个元素中删除k/2个,那么剩下的数组的第k-k/2小就是原来数组的第k小。我们通过比较两个数组的第k/2小来决定删除哪部分数据。
在写递归函数过程中,我们可以分别用i和j来表示数组1和数组2的开始位置,通过移动i和j来实现前面说的删除。然后可能会出现某数组的长度小于k/2的情况,不妨设数组1的长度小于k/2,那么我们就能知道数组2的前k/2个数据中不包含综合起来的第k小数据。于是删除数组2的前k/2个数据然后递归即可。
代码
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int m = nums1.size();
int n = nums2.size();
return (findkth(nums1,0,nums2,0,(m+n+1)/2)+findkth(nums1,0,nums2,0,(m+n+2)/2))/2.0;
}
int findkth(vector<int>& num1,int i,vector<int>& num2,int j,int k) {
if(i>=num1.size()) return num2[j+k-1];
if(j>=num2.size()) return num1[i+k-1];
if(k==1) return min(num1[i],num2[j]);
int temp1 = (i+k/2-1<num1.size())?num1[i+k/2-1]:INT_MAX;
int temp2 = (j+k/2-1<num2.size())?num2[j+k/2-1]:INT_MAX;
if(temp1<temp2) return findkth(num1,i+k/2,num2,j,k-k/2);
else return findkth(num1,i,num2,j+k/2,k-k/2);
}
};