0004 寻找两个有序数组的中位数
题目链接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays/
给定两个大小为 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
思路
- 要求时间复杂度为O(log(m+n)),就想到二分法
- 因为是两个从小到大的有序数组,查找中位数,就是查找第(nums1Size + nums2Size + 1) / 2和(nums1Size + nums2Size + 2) / 2两个数的均值
- 在两个数组查找第k个数,利用二分法,每次在两个数组查找第k/2个数,去掉小的那个数组前k/2个,再在接下来的数组中找,直到找到
- 注意边界条件,例如数组长度小于k/2
解法
1.C语言版
#define MIN(A, B) ((A) < (B) ? (A) : (B))
// 找到第K个数
int findKth(int* nums1, int nums1Size, int* nums2, int nums2Size, int k)
{
if(nums1Size == 0) return nums2[k-1];
if(nums2Size == 0) return nums1[k-1];
if(k == 1) return MIN(nums1[0], nums2[0]);
// 比较nums1和nums2的第k/2位,注意size比k/2小的情况
int i = MIN(nums1Size, k / 2), j = MIN(nums2Size, k / 2);
// 如果nums1的第i位大于nums2的第j位,那就去掉nums2的前j位,从nums2 + j开始,查找第k-j个
if (nums1[i - 1] > nums2[j - 1])
{
return findKth(nums1, nums1Size, nums2 + j, nums2Size - j, k - j);
} else
{
return findKth(nums1 + i, nums1Size - i, nums2, nums2Size, k - i);
}
return 0;
}
double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size) {
return (findKth(nums1, nums1Size, nums2, nums2Size, (nums1Size + nums2Size + 1) / 2) +
findKth(nums1, nums1Size, nums2, nums2Size, (nums1Size + nums2Size + 2) / 2) ) / 2.0;
}
2.Java版
/**
* 查找中位数
* @param nums1 数组1
* @param nums2 数组2
* @return
*/
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
return (findKthNum(nums1, 0, nums2, 0, (nums1.length + nums2.length + 1) / 2) +
findKthNum(nums1, 0, nums2, 0, (nums1.length + nums2.length + 2) / 2)) / 2.0;
}
/**
* 从有序数组中查找第k个的数
* @param nums1 数组1
* @param i 数组1要计算的起始位置
* @param nums2 数组2
* @param j 数组2要计算的起始位置
* @param k 查找第k个数
* @return 第k个数
*/
public int findKthNum(int[] nums1, int i, int[] nums2, int j, int k) {
if (i == nums1.length)
return nums2[j + k - 1];
if (j == nums2.length)
return nums1[i + k - 1];
if (k == 1)
return Math.min(nums1[i], nums2[j]);
int index1 = Math.min(i + k / 2, nums1.length);
int index2 = Math.min(j + k / 2, nums2.length);
if (nums1[index1 - 1] > nums2[index2 - 1])
return findKthNum(nums1, i, nums2, index2, k - index2 + j);
else
return findKthNum(nums1, index1, nums2, j, k - index1 + i);
}