给定两个大小分别为 m
和 n
的正序(从小到大)数组 nums1
和 nums2
。请你找出并返回这两个正序数组的 中位数 。
示例 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
提示:
nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-10^6 <= nums1[i], nums2[i] <= 10^6
双指针遍历,时间复杂度O(m+n)
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int n1 = nums1.length;
int n2 = nums2.length;
int p1 = 0;
int p2 = 0;
int result = 0;
int last = 0;
for(int i = 0;i <= (n1 + n2)/2;i++){
last = result;
if(p1 < n1 && (p2 >= n2 || nums1[p1] < nums2[p2])){
result = nums1[p1];
p1++;
}else{
result = nums2[p2];
p2++;
}
}
if((n1 + n2) % 2 != 0){
return result;
}else{
return (last + result) / 2.0;
}
}
}
注意点:
- 遍历次数。需要保证最后一次遍历得到的就是中位数(长度为奇数情况下),以nums1 = [1,3], nums2 = [2]为例,最后一次遍历要从else分支走出,所以遍历次数为(n1 + n2)/2。
- 数组越界问题。if的判断从左到右执行,不满足前面的条件就不会走到后面的,所以要把数组下标判断放在前面。
- 返回值类型。最后要除2.0,如果除2会丢失精度。
二分查找,时间复杂度O(log(m+n))
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int n1 = nums1.length;
int n2 = nums2.length;
if((n1 + n2) % 2 != 0){
return (double)getKth(nums1,nums2,(n1+n2)/2 + 1);
}else{
return (getKth(nums1,nums2,(n1+n2)/2) + getKth(nums1,nums2,(n1+n2)/2 + 1))/2.0;
}
}
public int getKth(int[] nums1,int[] nums2,int k){
int n1 = nums1.length;
int n2 = nums2.length;
int p1 = 0;
int p2 = 0;
int result = 0;
while(true){
if(p1 == n1){
result = nums2[p2 + k - 1];
break;
}
if(p2 == n2){
result = nums1[p1 + k - 1];
break;
}
if(k == 1){
result = Math.min(nums1[p1], nums2[p2]);
break;
}
if(nums1[Math.min(p1 + k/2,n1) - 1] <= nums2[Math.min(p2 + k/2,n2) - 1]){
int temp = k;
k -= (Math.min(p1 + k/2,n1) - p1);
p1 = Math.min(p1 + temp/2,n1);
}else{
int temp = k;
k -= (Math.min(p2 + k/2,n2) - p2);
p2 = Math.min(p2 + temp/2,n2);
}
}
return result;
}
}
log级别的时间复杂度一般都要用到二分法。
因为是有序数组,如果确定第i个数不是中位数,那么第0到第i-1个数也不可能是中位数,基于这个原理减少比较次数。
以奇数个数数组为例,中位数是两个有序数组中的第 (m+n)/2 个元素,也即求数组中第(m+n)/2 小的元素。
- 要找到第 k个元素,可以比较 nums1[k/2−1] 和 nums2[k/2−1]。这两个值前面共有 k/2−1 个元素。对于他们中的较小值,最多有k−2个数比它小,那么它就不可能是第k小的元素。
- 对于数组越界,需要根据实际排除的个数减少k的大小。
- 如果一个数组为空,则该数组中的所有元素都被排除,另一个数组中第 k 小的元素即为所求。
- 当k=1时,说明排除到了中位数的位置,两个数组指针位置的较小值即为中位数。