(4)Median of Two Sorted Arrays
题目:两个已经排好序的数组nums1和nums2,大小分别为m和n,求两个已排数组中位数。总运行时间复杂度应该是O(log(m+n))。
用例1:
nums1 = [1, 3]nums2 = [2]The median is 2.0
用例2:
nums1 = [1, 2]nums2 = [3, 4]The median is (2 + 3)/2 = 2.5
一看算法时间要求有log的情况下,第一反应就是二分法,从这道题来想,肯定是先排除一部分小于或大于某个数字的情况,然后再循环这样做,直到找到那个数字。
对于两个排好序的数组,尤其是这道题C++使用的是vector,那么我就想到了使用开始位置,总共长度和需要找到的第mid小的数字的mid,mid的来源就是(m+n+1)/2,这样可以求到要找的数字是第几小,然后查找nums1和nums2里面的数字,因为都是排好序的,如果在两个数组里面找不同长度的数组,会导致判断相当难,所以尽量和mid有关,那么就平均分配一下,预估两个数组合成数组时,为mid数字提供的小于mid的数字个数相同,首先对两个数组进行大小对比,了解哪个数组长度短,然后提取两个数组里的对比元素nums1_location = (mid+ 1)/2,同时nums2_location=mid - nums1_location。然后对nums1[nums1_location - 1 + start1_location],num2[nums2_location - 1 + start2_location] 进行对比,大的一项所在数组留下,小的一项数组需要将小的那部分切掉,然后继续做提取。
我们可以想一下,大的那部分,在合成的时候,肯定更靠近中位数,甚至是其中包含中位数,所以一定要留下,小于的那部分就可以切掉。这个想法成立的关键原因就在于两者提取的对比元素,前面的数字和一起是等于mid的,这样的话如果去掉前面的数字就相当于找到了合成后数组一半的数字。
那么就是简单的对比情况了,如果mid是等于1的话,那肯定就是找到现在两个数组里面最小的那个数字;如果提取出来的两个数字相同的话,那因为两个数字前面的数字个数和等于合成后的一半,所以要找的中位数正好就是提取出来的数字。
下面是我写的代码:
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int size1 = nums1.size(), size2 = nums2.size();
int zhong = (size1 + size2 + 1)/2;
int flag = (size1 + size2)%2;
if(flag == 0){
return (1.0*FindNum(nums1,nums2,0,0,size1,size2,zhong) + 1.0*FindNum(nums1,nums2,0,0,size1,size2,zhong+1))/2;
//return FindNum(nums1,nums2,0,0,size1,size2,zhong);
}
else{
return FindNum(nums1,nums2,0,0,size1,size2,zhong);
}
}
double FindNum(vector<int>& nums1, vector<int>& nums2, int start_nums1, int start_nums2, int size_nums1, int size_nums2, int mid){
int nums1_location = (mid + 1)/2 > size_nums1 ? size_nums1 : (mid + 1)/2;
int nums2_location = mid - nums1_location;
nums1_location += start_nums1;
nums2_location += start_nums2;
if(size_nums1 > size_nums2){
//printf("%d %d %d %d %d\n",start_nums2,start_nums1,size_nums2,size_nums1,mid);
return FindNum(nums2,nums1,start_nums2,start_nums1,size_nums2,size_nums1,mid);
}
if(size_nums1 == 0){
return nums2[mid - 1];
}
if(mid == 1){
return nums1[start_nums1] < nums2[start_nums2] ? nums1[start_nums1] : nums2[start_nums2];
}
if(nums1[nums1_location - 1] < nums2[nums2_location - 1]){
//printf("%d %d %d %d %d\n",nums1_location,start_nums2,size_nums1-nums1_location+start_nums1,size_nums2,mid-nums1_location+start_nums1);
return FindNum(nums1,nums2,nums1_location,start_nums2,size_nums1-nums1_location+start_nums1,size_nums2,mid-nums1_location+start_nums1);
}
else if(nums1[nums1_location - 1] > nums2[nums2_location - 1]){
//printf("%d %d %d %d %d\n",start_nums1,nums2_location,size_nums1,size_nums2-nums2_location+start_nums2,mid-nums2_location+start_nums2);
return FindNum(nums1,nums2,start_nums1,nums2_location,size_nums1,size_nums2-nums2_location+start_nums2,mid-nums2_location+start_nums2);
}
else{
return nums1[nums1_location - 1];
}
}
};