分治法
题目链接:https://leetcode.com/problems/median-of-two-sorted-arrays/description/
本来上个星期就想做这一题的,试一下hard的难度,想了半天,还是只想出一种朴素的方法:用两个标记分别指向两个vector的begin,这样一个个比较下去,直到数到中位数为止。
也可以类似这道题目一样:http://blog.csdn.net/xxhi008/article/details/77967221,将两个vector合起来再去找中值。
但前面做法的时间复杂度应该是O(m+n),不是题目所要的log(m+n),于是便看了一下discussion,觉得以下这种做法比较优美简洁,反复研究了几天,将思考与大家分享一下。
vector是有nums1,nums2,大小分别为size1,size2。
大体思路是这样的:先假设size1与size2都大于k/2,那么找出nums1[k/2-1]与nums2[k/2-1]比较他们的大小。
如果nums1[k/2-1] < nums2[k/2-1],就说明nums1[k/2-1]前面的nums1[0]到nums1[k/2-1]都比要找的中值要小,即是可以省去的。
同理 nums1[k/2-1] > nums2[k/2-1]也一样处理。
当 nums1[k/2-1] == nums2[k/2-1]时,就说明这两个值就是我们要找的第k大的数,因为前面已经有k-2个数。
几点注意的地方:
1.我们始终保持nums1为较少数目的vector,这样易于处理。
2.当size1 < k/2时,就取出nums1[size1-1]来处理。
3.我们做的省去的操作的时间复杂度十分低,符合题目要求。
//在做《算法概论》的时候发现,2.22给出了相应的证明,把大神的证明贴在这里
4.递归终止条件1:当size1 == 1时,说明第一个vector全省去了,取nums2[k-1]即为所求
5.递归终止条件2:当k == 1时,说明只要找第1小的数,所以取nums1[0]与nums2[0]的最小值即可。
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int size1 = nums1.size(),size2 = nums2.size();
if((size1 + size2) % 2 != 0)
return find(nums1,size1,nums2,size2,(size1+size2)/2 + 1);
else
return (find(nums1,size1,nums2,size2,(size1+size2)/2) + find(nums1,size1,nums2,size2,(size1+size2)/2 + 1)) / 2 ;
}
double find(vector<int> nums1,int size1,vector<int> nums2,int size2,int k)
{
if(size1 > size2)//保持第一个数组始终较小数目,便于处理
return find(nums2,size2,nums1,size1,k);
if(size1 == 0)//递归终止条件1:数目较少的数组全部舍弃完,只剩下一个数组
return nums2[k-1];
if(k == 1)//递归终止条件2:k==1,即求两个数组中最小值
return min(nums1[0],nums2[0]);
int temp1 = min(k/2,size1),temp2 = k - temp1;
if(nums1[temp1-1] > nums2[temp2-1])
return find(nums1,size1,vector<int>(nums2.begin() + temp2,nums2.end()),size2 - temp2,k-temp2);
else if(nums1[temp1-1] < nums2[temp2-1])
return find(vector<int>(nums1.begin() + temp1,nums1.end()),size1 - temp1,nums2,size2,k-temp1);
else// if(nums1[temp1] == nums2[temp2])
return nums1[temp1-1];
}
};