题目:
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。
示例 1:
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:
输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
示例 3:
输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000
示例 4:
输入:nums1 = [], nums2 = [1]
输出:1.00000
示例 5:
输入:nums1 = [2], nums2 = []
输出:2.00000
方法:二分查找
当两个数组总长度为奇数时,中位数表示为第 numsSize/2+1 个元素,当数组长度为偶数时,中位数则为第 numsSize/2 个元素和第 numsSize/2+1 个元素的平均数。因此,我们可以理解这道题是查找第 k 小的数,k 则表示 numsSize/2 或 numsSize/2+1 。
以一个例子来解释一波
A : 1 3 4 9
B : 1 2 3 4 5 6 7 8 9
两数组长度为13,所以 k 为 7,有两个数组,所以我们可以把 k 二分,分别在两个数组里排除缩短时间,最多也只会有 A[0...k/2-1] 和 B[0...k/2-1] 个元素被排除,进而缩小范围,找到答案。(词穷了有点,不知道咋描述,可以看官方解析)
所以,第一次二分,我们需要找到两个数组中下标为 k/2-1=2 的数,即 A[2] ,B[2]
A : 1 3 4 9
B : 1 2 3 4 5 6 7 8 9
显然,A[2] >B[2] ,所以,B[0] 到 B[2] 一定不会是我们要找的第 k 个数,将其排除
同时,更新 k 值,k = k- k/2 =4。
第二次二分,k/2 -1=1, 即 A[1] B[4]
A : 1 3 4 9
B : 1 2 3 4 5 6 7 8 9
A[1] < B[4] ,同理,排除 A[0] 和 A[1],k = 2
第三次二分,k/2 -1 =0, 即 A[2] B[3]
A : 1 3 4 9
B : 1 2 3 4 5 6 7 8 9
相等了,随意排除一个就可以,假设排除 A
k = k - k/2 =1
k =1 了,这个时候,我们就只需要找两个数组中较小的那个,就是我们要找的第 k 个数。
A : 1 3 4 9
B : 1 2 3 4 5 6 7 8 9
所以,B[3] = 4 就是我们要找的答案。
代码:
int erfen(int *nums1,int *nums2, int nums1Size,int nums2Size, int k){
int i=0,j=0; //i,j 记住 k/2-1 的老位置,方便下一次改变
while(true){
//边界情况,只有一边存在数字,直接返回另一个数组的中值即可
if(nums1Size==i){
return nums2[j+k-1];
}
if(nums2Size==j){
return nums1[i+k-1];
}
//最后一步就要找到结果了,返回两个值中较小的一个,就是结果
if(k==1){
return nums1[i]>nums2[j]?nums2[j]:nums1[i];
}
//中间不断判断更新k值的过程
int newi =(i + k / 2 - 1)>(nums1Size - 1)?nums1Size - 1:(i + k / 2 - 1);
int newj =(j + k / 2 - 1)>(nums2Size - 1)?nums2Size - 1:(j + k / 2 - 1);
int pivot1 = nums1[newi];
int pivot2 = nums2[newj];
//比较这两个数
if (pivot1 <= pivot2) {
k -= newi - i + 1;
i = newi + 1;
}
else {
k -= newj - j + 1;
j = newj + 1;
}
}
}
double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size){
int numsSize=nums1Size+nums2Size;
if(numsSize%2==1){
return(erfen(nums1,nums2,nums1Size,nums2Size,(numsSize+1)/2));
}
else{
return (erfen(nums1, nums2,nums1Size, nums2Size,numsSize / 2) + erfen(nums1,nums2,nums1Size,nums2Size, numsSize / 2 + 1)) / 2.0; //PS:2.0很重要,要注意小数
}
}