Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
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
两个方法找到两个排序数组的中位数,方法一思路是把两个数组合并成一个数组,然后求中值。这里需要注意的就是当数组个数为偶数时,要除以2.0,最后才能得到double值,否则只能得到整数部分。花费时长6ms。
public class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;
int[] nums3 = new int[m + n];
int i = 0;
int j = 0;
int k = 0;
while(i < m && j < n){
if(nums1[i] < nums2[j]){
nums3[k] = nums1[i];
i++;
}else if(nums1[i] > nums2[j]){
nums3[k] = nums2[j];
j++;
}else{
nums3[k] = nums1[i];
nums3[++k] = nums2[j];
i++;
j++;
}
k++;
}
if(i == m){
for(int t = j; j < n; j++){
nums3[k] = nums2[j];
k++;
}
}
if(j == n){
for(int t = i; i < m; i++){
nums3[k] = nums1[i];
k++;
}
}
if(k % 2 == 0){
return (nums3[k/2] + nums3[k/2-1]) / 2.0;
}else{
return nums3[(k-1)/2];
}
}
}
方法二,在discuss中看到一种更为普通的解法,且效率更好。4ms。以下为我的翻译~
首先我们需要明白中位数的作用是什么,它将一个集合分成长度相等的两部分,一边比另一边大。
我们在位置i将A数组分成两部分,A的元素个数为m,共有i=(0~m) m+1个划分位置,len(left_A)=i,len(right_A)=m-i,当i=0时,left_A是空的,当i=m时right_A是空的。
同理,在j位置将B数组划分,B的元素个数是n。
将left_A和left_B放到一组,right_A和right_B放到一组,命名为left_part和right_part。前提是保证m <= n 否则在运行过程中,数组下标会越界。
如果我们能确保
那么就可以得到中位数 median = (max(left_part) + min(right_part))/2.
为了保证上述两个条件,我们只需保证
(假设对所有的A[i-1],B[j-1],A[i],B[j]都是合法的,i=0 或 m, j=0 或 n的情况再单独讨论)
所以我们需要做的就是在i=(0~m)中,找到一个合适的i,使得B[j-1] <= A[i] and A[i-1] <= B[j] (j = (m+n+1)/2-i)。
算法如下:
- 使imin = 0, imax = m,在[imin, imax]中找合适的i;
- 使i = (imin + imax) / 2,j = (m + n + 1) / 2 - i;
- 现在已经保证了len(left_part) == len(right_part),接下来只有3中情况需要讨论:
public class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;
if(m > n){ // 保证m <= n的
int[] temp = nums1;
nums1 = nums2;
nums2 = temp;
int t = m;
m = n;
n = t;
}
int imin = 0;
int imax = m;
int i, j, max_of_left, min_of_right;
double mid=0;
while(imin <= imax){
i = (imin + imax) / 2;
j = (m + n + 1) / 2 - i;
if(j > 0 && i < m && nums2[j - 1] > nums1[i]){ // 当i偏小时
imin = i + 1;
}else if(i > 0 && j < n && nums1[i - 1] > nums2[j]){ // 当i偏大时
imax = i - 1;
}else{<span style="white-space:pre"> </span>// i在合适位置
if(i == 0){
max_of_left = nums2[j - 1];
}else if(j == 0){
max_of_left = nums1[i - 1];
}else{
max_of_left = Math.max(nums1[i - 1], nums2[j - 1]);
}
if((m + n) % 2 ==1){
mid = max_of_left;
break;
}
if(i == m){
min_of_right = nums2[j];
}else if(j == n){
min_of_right = nums1[i];
}else{
min_of_right = Math.min(nums1[i], nums2[j]);
}
mid = (max_of_left + min_of_right) / 2.0;
break;
}
}
return mid;
}
}