0. 题目
题目: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)).
1. 步骤
假设这两个数组的大小分别为m (nums1)和
- 首先要有最差的解法,即不考虑时间复杂度O(log(m+n))
- 解法1-思路:使用合并排序中的merge函数,将两个有序数组合并为一个有序数组,而后返回中位数。此时时间复杂度为O(n+m)
- 其次,再找较优秀的解法
- 解法2-思路: 时间复杂度为O(log(m+n),两个数组又是有序的数组,故考察的应该是二分查找;
2. 优化思路
题目其实可以拓展为求两个有序数组第k大元素。假设我们有一个函数可以用来返回合并数组的第k大元素,那么就变成了这样:
- 如果
m+n 是奇数,则找合并数组的第(m+n)/2
大元素- 如果 m+n 是偶数,则返回
(m+n)/2
大元素和第(m+n)/2+1
大元素
如何求两个有序数组的第
k
大元素? 我们可以每次取两个数组的前k/2
个元素,比较两个数组的第k/2
个元素的大小,而后决定删除哪一个数组的前k/2
个元素。因为第k
大元素肯定不可能在第2/k
个元素较小的那个数组的前k/2
个元素之中。算法步骤如下:每一次取nums1和nums2的前k/2个元素,比较
nums1[k/2]
与nums2[k/2]
的大小if(nums1[k/2] <= nums2[k/2] )
,则删除nums1[0~k/2]
之间的元素,第k
个元素不可能在该区间,同时也要更新k
- 反之,则删除
nums2[0~k/2]
之间的元素,更新k
- 递归地进行上述操作,直到找到第
k
个元素为止
3. 容易出错的地方
基本上就是递归的终止条件,非常容易出错。要注意如下几点:
- 当
nums1.size()<k/2
和nums2.size()<k/2
的时候,要如何处理? - 当
k==1
的时候要如何处理? - 上述两个条件都不满足的时候要如何处理?
- 每一删除数组中一个区间,数组的边界如何处理?
4. 代码如下
- 方法1:
class Solution1 { //时间复杂度为o( size(x1) + size(x2) ) public: void merge(vector<int> &des,vector<int>&x1,vector<int>&x2){ int _size=des.size(); int i,j,k; i=0; j=0; k=0; while(i<x1.size() && j<x2.size() ){ if(x1[i]<x2[j]){ des[k++]=x1[i++]; }else{ des[k++]=x2[j++]; } } if(i<x1.size()) { for(;i<x1.size();++i){ des[k++]=x1[i]; } }else{ for(;j<x2.size();++j){ des[k++]=x2[j]; } } } double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { vector<int> des(nums1.size()+nums2.size(),0); merge(des,nums1,nums2); int middle=( des.size()-1 )/2; if(des.size()%2==0){ return double(des[middle]+des[middle+1])/2; }else{ return des[middle]; } } };
- 方法2:
class Solution2 { public: // 非递归形式 边界这块不好写 不用考虑奇数偶数问题只需要返回一个值就好了 int findKth(vector<int>&nums1,int low1,int high1,vector<int>&nums2,int low2,int high2,int k){ if(low1>high1) return nums2[low2+k-1]; if(low2>high2) return nums1[low1+k-1]; if(k==1) { return min(nums1[low1],nums2[low2]); } int mid=k/2-1; if( (low1+mid)>high1){ if( nums1[high1]<=nums2[low2+mid] ){ k=k-(high1-low1+1); return nums2[low2+k-1]; }else{ k=k-(mid+1); low2 += mid+1; return findKth(nums1,low1,high1,nums2,low2,high2,k); } } if((low2+mid)>high2 ){ if( nums2[high2]<=nums1[low1+mid] ){ k=k-(high2-low2+1); return nums1[low1+k-1]; }else{ k=k-(mid+1); low1 += mid+1; return findKth(nums1,low1,high1,nums2,low2,high2,k); } } if( nums1[ low1 + mid ] <= nums2[ low2 + mid ]) { low1=low1+mid+1; k=k-(mid+1); }else{ low2=low2+mid+1; k=k-(mid+1); } return findKth(nums1,low1,high1,nums2,low2,high2,k); } double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { int _size=nums1.size()+nums2.size(); int mid=(_size+1)/2; double res=0; if(_size%2==0){ res=(double)findKth(nums1,0,nums1.size()-1,nums2,0,nums2.size()-1,mid); cout<<res<<endl; res += (double)findKth(nums1,0,nums1.size()-1,nums2,0,nums2.size()-1,mid+1); res=res/2; }else{ res=(double)findKth(nums1,0,nums1.size()-1,nums2,0,nums2.size()-1,mid); } return res; } };
- 如果 m+n 是偶数,则返回