题目描述
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
示例 1:
nums1 = [1, 3]
nums2 = [2]
则中位数是 2.0
示例 2:
nums1 = [1, 2]
nums2 = [3, 4]
则中位数是 (2 + 3)/2 = 2.5
解题思路
总体上采用二分法,理论上当我们确定了一个数组的切分位置时,另一个数组的切分位置也随之确定,因此,为了减少操作次数,我们可以选择数组长度较小的数组进行操作。设置变量cut1用来指示nums1的切分位置,cut2用来指示nums2的切分位置,cutL和cutR用来表示cut1的切分范围。L1,R1用来指示cut1切分位置左右两边的值,L2,R2用来指示cut2切分位置左右两边的值。根据正常情况下L1应该小于R2,R1应该大于L2。我们可以根据这个来进行判断我们的切分位置是否正确。然后根据总的位数是否是偶数,奇数来进行相应的计算。
代码如下
package leetcode;
public class MedianofTwoSortedArrays {
/**
* 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 by only 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
*
* 最优解时间复杂度:O(log min((m+n)) )
*
* num1: 3 5 8 9
* num2: 1 2 7 10 11 12
* @param nums1
* @param nums2
* @return
*/
public double findMedianSortedArrays(int[] nums1,int[] nums2){
// 知道一个数组的数量越少,可以节省操作次数,减少时间复杂度
if(nums1.length > nums2.length){
return findMedianSortedArrays(nums2,nums1);
}
int len = nums1.length + nums2.length;
int cut1 = 0;
int cut2 = 0;
int cutL = 0; // 划分范围
int cutR = nums1.length;
while (cut1 <= nums1.length){
cut1 = (cutR - cutL)/2 + cutL;
cut2 = len/2 - cut1;
double L1 = (cut1 == 0)?Integer.MIN_VALUE : nums1[cut1-1];
double L2 = (cut2 == 0)?Integer.MIN_VALUE : nums2[cut2-1];
double R1 = (cut1 == nums1.length)?Integer.MAX_VALUE : nums1[cut1];
double R2 = (cut2 == nums2.length)?Integer.MAX_VALUE : nums2[cut2];
if(L1 > R2){ // 当划分位置不正确时进行相应的移动
cutR = cut1 - 1;
}else if(L2 > R1){
cutL = cut1 + 1;
}else{
if(len % 2 == 0){ // 根据奇偶来进行相应的计算
L1 = L1 > L2 ? L1:L2;
R1 = R1 < R2 ? R1:R2;
return (L1 + R1)/2;
}else{
R1 = (R1 < R2) ? R1 : R2;
return R1;
}
}
}
return -1;
}
}