给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。
请你找出这两个正序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
方法一:暴力解法(不符合时间复杂度要求)
时间复杂度O(m+ n) 空间复杂度O(m + n)
package Algorithm;
public class findMedianSortedArrays1 {
public int[] num1;
public int[] num2;
public double findMedianSortedArrays(int[] num1, int[] num2){
this.num1 = num1;
this.num2 = num2;
//这里n1和n2保存的是两个数组的元素个数
int n1 = num1.length - 1;
int n2 = num2.length - 1;
int[] add = new int[n1 + n2 + 2];
if (n1 == 0){
if (n2 % 2 == 0){
return (num2[n2/2] + num2[n2/2 + 1]) / 2.0;
}
else return num2[n2/2];
}
if (n2 == 0){
if (n1 % 2 == 0){
return (num2[n1/2] + num2[n1/2 + 1]) / 2.0;
}
else return num2[n1/2];
}
int count = 0;
int i = 0;
int j = 0;
while (i != n1 && j != n2){
if (num1[i] < num2[j]){
add[count++] = num1[i++];
}
else add[count++] = num2[j++];
}
while (i <= n1){
add[count++] = num1[i++];
}
while (j <= n2){
add[count++] = num2[j++];
}
if (add.length % 2 == 0){
return (add[(n1 + n2)/2] + add[(n1 + n2)/2 + 1]) / 2.0;
}
else return add[(n1 + n2)/2];
}
}
测试代码:
public class findMedianSortedArrays1Test {
public static void main(String[] args) {
int[] num1 = {1, 3, 4 ,9};
int[] num2 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
findMedianSortedArrays1 fms = new findMedianSortedArrays1();
System.out.println(fms.findMedianSortedArrays(num1, num2));
int[] num3 = {1, 2};
int[] num4 = {3, 4};
findMedianSortedArrays1 fms1 = new findMedianSortedArrays1();
System.out.println(fms1.findMedianSortedArrays(num3, num4));
}
}
方法二:
假设我们要找第 k 小数,我们可以每次循环排除掉 k/2 个数。
从上边可以看到,无论是找第奇数个还是第偶数个数字,对我们的算法并没有影响,而且在算法进行中,k 的值都有可能从奇数变为偶数,最终都会变为 1 或者由于一个数组空了,直接返回结果。
所以我们采用递归的思路,为了防止数组长度小于 k/2,所以每次比较 min(k/2,len(数组) 对应的数字,把小的那个对应的数组的数字排除,将两个新数组进入递归,并且 k 要减去排除的数字的个数。递归出口就是当 k=1 或者其中一个数字长度是 0 了。
链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-w-2/
package Algorithm;
import javax.swing.*;
public class findMedianSortedArrays2 {
int[] num1;
int[] num2;
public double findMedianSortedArrays2(int[] num1, int[] num2){
this.num1 = num1;
this.num2 = num2;
int n1 = num1.length;
int n2 = num2.length;
//若为偶数我们则需要求左中位数和右中位数取平均
int left = (n1 + n2 + 1) / 2;
int right = (n1 + n2 + 2) / 2;
//这样若总长度为偶数则计算出left和right,若为奇数则计算两遍取平均
return (getKth(num1, 0, n1 - 1, num2, 0, n2 - 1, left) +
getKth(num1, 0, n1 - 1, num2, 0, n2 - 1, right)) / 2.0;
}
private int getKth(int[] num1, int from1, int to1, int[] num2, int from2, int to2, int k){
int len1 = to1 - from1 + 1;
int len2 = to2 - from2 + 1;
//为了确保我们如果有空数组,那么空数组一定为num1
if (len1 > len2){
return getKth(num2, from2, to2, num1, from1, to1, k);
}
if (len1 == 0){
//如果数组1为空,那么只需要求得数组2中第k大的数字
return num2[from2 + k - 1];
}
if (k == 1){
//如果最后两个数组都只保存一个数字时,比较他俩的大小,选择更小的那个
return Math.min(num1[from1], num2[from2]);
}
//判断当前数组长度是否小于k,如果小于,则取当前数组最后一个元素
int i = from1 + Math.min(len1, k / 2) - 1;
int j = from2 + Math.min(len2, k / 2) - 1;
if (num1[i] < num2[j]){
return getKth(num1, i + 1, to1, num2, from2, to2, k - (i - from1 + 1));
}
else return getKth(num1, from1, to1, num2, j + 1, to2, k - (j - from2 + 1));
}
}
测试代码:
package Test;
import Algorithm.findMedianSortedArrays1;
import Algorithm.findMedianSortedArrays2;
public class findMedianSortedArrays2Test {
public static void main(String[] args) {
int[] num1 = {1, 3, 4 ,9};
int[] num2 = {1, 2, 3, 4, 5, 6, 7, 8, 9};
findMedianSortedArrays2 fms = new findMedianSortedArrays2();
System.out.println(fms.findMedianSortedArrays2(num1, num2));
int[] num3 = {1, 2};
int[] num4 = {3, 4};
findMedianSortedArrays2 fms2 = new findMedianSortedArrays2();
System.out.println(fms2.findMedianSortedArrays2(num3, num4));
}
}