参考博客:https://blog.csdn.net/xu2645318400/article/details/73924591
题目:
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
分析:同样卡了我好久的题。。。
题目大意就是求两个升序序列的中位数(中位数:若奇数序列为中间的元素值,偶数序列为中间两个元素的均值~)
这题要求了时间复杂度O(log(m+n)),看到这种时间复杂度想到的方法就应该是二分法,当然想起了王道上的一道求两等长升序序列S1,S2中位数的题,当时的做法是每次淘汰S1中的一半元素与S2中的一半元素,当然要保证每次S1 S2淘汰的元素个数是相同的,多了不赘述,回归本题。。。
由于本题是不等长的两个升序序列,而且还存在其中一个数组为空的情况,考虑方法就有所不同。将本题的求中位数转换成求两序列排序后的第k(k = 两数组长度和加一 / 2)个数,也就是中位数所在的位置,但是中位数有的时候是两数的均值,那么第一个数的位置为两数组长度和加一/2,第二个数的位置为多少?答案是 两数组长度和加二/2(可以自行检测)当两数组长度和为奇数的时候以上的两数值相同,为偶数的时候两数值差一,所以中位数=(两数组长度和加一/2 个元素+ 两数组长度和加二/2个元素)/ 2
思路:
二分法,每次尽量排除一个数组中的前一半比较小的元素,递归。。
分治法,对每次排除元素时采取不同的动作
递归边界:
1、其中一个数组为空或元素均已淘汰
if(low1 == m) //nums1数组为空或者说元素都已排除
return nums2[low2 + k - 1] ;
if(low2 == n) //nums2数组为空或者说元素都已排除
return nums1[low1 + k - 1] ;
2、若查找第k个元素,k为1 或者是已递归至1
if(k == 1) //要找两数组中的第一个元素,则返回两数组中最小的元素
return nums1[low1]<nums2[low2] ? nums1[low1] : nums2[low2] ;
递归条件:
1、保证其中一个数组短,防止溢出访问(比如要取第k / 2个元素时,有一个数组的长度小于k / 2,那么就访问溢出了,踩坑的我。。。),解决办法就是让每次淘汰的元素等于min(最短的数组,k/2)
p1代表短数组能淘汰的元素个数,即 p1= min(最短的数组,k/2)
p2代表长数组能淘汰的元素个数,并保证每次淘汰k/2个元素,所以 p2 = k/2 - p1
2、nums1[low1 + p1 - 1] < nums2[low2 + p2 - 1],更新low值与k值
由于每次淘汰的是前面比较小的数,所以数组的起始位置未必是0
low值就是用来记录数组起始位置的元素
3、nums1[low1 + p1 - 1] <= nums2[low2 + p2 - 1],更新low值与k值
代码:
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int low1 = 0 , low2 = 0 , m = nums1.size() , n = nums2.size() , k = (m + n + 1) / 2 ;
double res ;
res = getMedian(nums1, nums2, low1, m, low2, n, k);
res += getMedian(nums1, nums2, low1, m, low2, n, (m + n + 2) / 2);
return res / 2 ;
}
int getMedian(vector<int>& nums1, vector<int>& nums2, int low1, int m, int low2, int n, int k){
if(low1 == m)
return nums2[low2 + k - 1] ;
if(low2 == n)
return nums1[low1 + k - 1] ;
if(k == 1)
return nums1[low1]<nums2[low2] ? nums1[low1] : nums2[low2] ;
if(m - low1 > n - low2)
return getMedian(nums2, nums1, low2, n, low1, m, k);
int p1 = (m - low1) < k / 2 ? m - low1 : k / 2 ;
int p2 = k - p1 ;
if(nums1[low1 + p1 - 1] < nums2[low2 + p2 - 1]){
low1 += p1 ;
k -= p1 ;
}
else{
low2 += p2 ;
k-= p2 ;
}
return getMedian(nums1, nums2, low1, m, low2, n, k);
}
};