给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
时间: 2024-05-25 11:18:56 浏览: 89
解法一:暴力合并排序
将两个数组合并成一个有序数组,然后根据数组长度的奇偶性返回中位数。
时间复杂度:O((m+n)log(m+n)),其中 m 和 n 分别是两个数组的长度,排序需要 O((m+n)log(m+n)) 的时间。
空间复杂度:O(m+n),需要一个额外的数组存储两个数组合并后的结果。
解法二:二分查找
根据中位数的定义,当 m+n 为奇数时,中位数为两个有序数组中的第 (m+n)/2 个元素;当 m+n 为偶数时,中位数为两个有序数组中的第 (m+n)/2 个元素和第 (m+n)/2+1 个元素的平均值。因此,可以考虑使用二分查找的方法查找第 k 小的元素。
我们假设两个数组的长度分别为 m 和 n,且 m<=n,需要在 nums1 和 nums2 两个有序数组中找到第 k 小的元素。首先,设 i=min(m,k/2),j=k-i,则有 nums1[i-1]<=nums2[j-1]。如果 nums1[i-1]>nums2[j-1],那么 nums2[0...j-1] 中的所有元素都小于第 k 小的元素,可以将这些元素全部排除。因为第 k 小的元素不可能在 nums2[0...j-1] 中,否则 nums2[0...j-1] 中就已经有 k 个元素了,而 nums1 中只有 i-1 个元素小于 nums1[i-1]。因此,可以将 nums2[0...j-1] 排除,并更新 k 的值为 k-j。同理,如果 nums1[i-1]<=nums2[j-1],那么 nums1[0...i-1] 中的所有元素都小于第 k 小的元素,可以将这些元素全部排除,更新 k 的值为 k-i。
时间复杂度:O(log(m+n)),其中 m 和 n 分别是两个数组的长度,每次循环可以排除当前 k/2 个元素,因此循环次数为 O(log(m+n))。
空间复杂度:O(1),只需要常数级别的额外空间。
参考代码:
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int m = nums1.size();
int n = nums2.size();
int left = (m + n + 1) / 2; // 如果 m+n 是奇数,则中位数是第 (m+n)/2+1 个元素;如果是偶数,则中位数是第 (m+n)/2 个和第 (m+n)/2+1 个元素的平均值
int right = (m + n + 2) / 2; // 如果 m+n 是奇数,则中位数是第 (m+n)/2+1 个元素;如果是偶数,则中位数是第 (m+n)/2 个和第 (m+n)/2+1 个元素的平均值
return (findKth(nums1, 0, m - 1, nums2, 0, n - 1, left) + findKth(nums1, 0, m - 1, nums2, 0, n - 1, right)) / 2.0;
}
int findKth(vector<int>& nums1, int start1, int end1, vector<int>& nums2, int start2, int end2, int k) {
int len1 = end1 - start1 + 1;
int len2 = end2 - start2 + 1;
if (len1 > len2) {
return findKth(nums2, start2, end2, nums1, start1, end1, k);
}
if (len1 == 0) {
return nums2[start2 + k - 1];
}
if (k == 1) {
return min(nums1[start1], nums2[start2]);
}
int i = start1 + min(len1, k / 2) - 1;
int j = start2 + min(len2, k / 2) - 1;
if (nums1[i] > nums2[j]) {
return findKth(nums1, start1, end1, nums2, j + 1, end2, k - (j - start2 + 1));
} else {
return findKth(nums1, i + 1, end1, nums2, start2, end2, k - (i - start1 + 1));
}
}
};