LeetCode 4. Median of Two Sorted Arrays (Hard)
题目
Given two sorted arrays nums1 and nums2 of size m and n respectively, return the median of the two sorted arrays.
The overall run time complexity should be O(log (m+n)).
Example 1:
Input: nums1 = [1,3], nums2 = [2]
Output: 2.00000
Explanation: merged array = [1,2,3] and median is 2.
Example 2:
Input: nums1 = [1,2], nums2 = [3,4]
Output: 2.50000
Explanation: merged array = [1,2,3,4] and median is (2 + 3) / 2 = 2.5.
Constraints:
nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-106 <= nums1[i], nums2[i] <= 106
思路:
解法(Java):
由于题目中限定了时间复杂度为O(log(m+n)),所以采用二分法。
首先考虑取两个数组所有元素中第k大的数,k从1开始。
A [ 1 ],A [ 2 ],A [ 3 ],A [ k / 2] ... ,
B[ 1 ],B [ 2 ],B [ 3 ],B[ k / 2] ... ,
如果 A [ k / 2 ] < B [ k / 2 ] ,那么 A [ 1 ],A [ 2 ],A [ 3 ],A [ k / 2] 都不可能是第 k 小的数字。
推导:A 数组中比 A [ k / 2 ] 小的数有 k / 2 - 1 个,B 数组中,B [ k / 2 ] 比 A [ k / 2 ] 大,假设 B [ k / 2 ] 前边的数字都比 A [ k / 2 ] 小,也只有 k / 2 - 1 个,所以比 A [ k / 2 ] 小的数字最多有 (k / 2 - 1) + (k / 2 - 1) = k - 2 个,所以 A [ k / 2 ] 最多是第 k - 1 小的数。而比 A [ k / 2 ] 小的数更不可能是第 k 小的数了,所以可以把它们排除。
递归边界情况:
假设数组nums1长度始终小于数组nums2
nums1长度为0,直接返回nums2中第k大的值。
当k = 1,取nums1和nums2两者的最小值。
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length, n = nums2.length;
//求中位数,若总数为奇数,则中位数为中间元素,
//若为偶数,则为中间两个元素的平均数
//这里统一起来,
//奇数时,left和right其实指的是同一个数
//偶数时,left代表中位数左边那个数,right代表右边那个数
//left和right的值代表数是第几大(从1开始)
int left = (m+n+1)/2, right = (m+n+2)/2;
double res = getKth(nums1, 0, m-1, nums2, 0, n-1, left);
//两个数组元素总是是奇数的情况
if(left == right) return res;
//偶数情况
res = (res + getKth(nums1, 0, m-1, nums2, 0, n-1, right))/2;
return res;
}
private double getKth(int[] nums1, int start1, int end1, int[] nums2, int start2, int end2, int k){
int len1 = end1 - start1 + 1;
int len2 = end2 - start2 + 1;
// 使nums1始终是长度小的那个数组
if(len1 > len2) return getKth(nums2, start2, end2, nums1, start1, end1, k);
if(len1 == 0) return nums2[start2 + k -1];
if(k == 1) return Math.min(nums1[start1], nums2[start2]);
// 当nums1长度小于k/2,为防止数组下标越界,则i取最后一个数下标
int i = start1 + Math.min(len1, k/2) - 1;
// 因为nums2始终比nums1长, j其实不会越界
int j = start2 + Math.min(len2, k/2) - 1;
if(nums1[i] < nums2[j]){
return getKth(nums1, i + 1, end1, nums2, start2, end2, k - (i - start1 + 1));
}else{
return getKth(nums1, start1, end1, nums2, j + 1, end2, k - (j - start2 + 1));
}
}
}
感谢以下参考:

浙公网安备 33010602011771号