题目描述
给定两个大小分别为 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
提示:
nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106
解题思路
**划分数组:**首先需要理解中位数是什么。
将一个集合划分为两个长度相等的子集,其中一个子集中的元素总是大于另一个子集中的元素。
- 那么一个数组找中位数,我们就可以对中位数分割,例如 [1 2 3 4],中位数就是 2 3,目标就是寻找 2 3。
- 左半部分的数都大于右半部分的数。
- 左部分的数要等于右半部分的个数,但是如果长度为奇数,就让左半部分比右半部分多一个数,分割左边的数就是想要的中位数。
- 扩展到两个数组的时,如[1 2 3 4] [5 6 7 8 9 10 11 12]。
- 1 2 3 4 ||
5 6 || 7 8 9 10 11 12 - 知道第一个数组的分割线就可以求得第二个数组的分割线。
- 在偶数的情况下:第一个数组的长度为 n 分割线前面有 i 个元素,第二个数组的长度为 m 分割线前面有 j 个元素,两个数组分割线左部分的元素的个数和等于右部分的分割线的和,j = (m + n) / 2 - i。
- 在奇数的情况下:左部分多一个元素, i + j = n - i + m - j + 1,左部分多要在右部分 + 1 才能使左右部分元素个数相等,即 j = (m + n + 1) / 2 - i。
- 如 [1 2 3 4] [5 6 7 8 9 10 11 12 13]
- 1 2 3 4 ||
5 6 7 || 8 9 10 11 12 13 - 但是 i 和 j 为整型,+1 在除以 2 不影响结果,所以总长度奇偶数都可以使用 j = (m + n + 1) / 2 - i。(即 13 / 2 = 6)
/**
* @ClassName FindMedianSortedArrays
* @Description 寻找两个正序数组的中位数
* @Version 1.0.0
* @Date 2024/6/3 23:54
* @Author By Dwl
*/
public class FindMedianSortedArrays {
public static void main(String[] args) {
int[] numsOne = new int[]{1, 2};
int[] numsTwo = new int[]{3, 4};
double d = findMedianSortedArrays(numsOne, numsTwo);
System.out.println(d);
}
public static double findMedianSortedArrays(int[] numsOne, int[] numsTwo) {
if (numsOne.length > numsTwo.length) {
return findMedianSortedArrays(numsTwo, numsOne);
}
// 获取长度下标
int m = numsOne.length;
int n = numsTwo.length;
// 定位指针
int left = 0, right = m;
// 获取中位数
int medianOne = 0, medianTwo = 0;
while (left <= right) {
// 获取中位数的指针
int i = (left + right) / 2;
// 取中位数旁边的指针
int j = (m + n + 1) / 2 - i;
// 获取中位数的值
int numsIm = (i == 0 ? Integer.MIN_VALUE : numsOne[i - 1]);
int numsI = (i == m ? Integer.MAX_VALUE : numsOne[i]);
int numsJm = (j == 0 ? Integer.MIN_VALUE : numsTwo[j - 1]);
int numsJ = (j == n ? Integer.MAX_VALUE : numsTwo[j]);
if (numsIm <= numsJ) {
medianOne = Math.max(numsIm, numsJm);
medianTwo = Math.min(numsI, numsJ);
left = i + 1;
} else {
right = i - 1;
}
}
return (m + n) % 2 == 0 ? (medianOne + medianTwo) / 2.0 : medianOne;
}
}