给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。 算法的时间复杂度应该为 O(log (m+n)) 。 这个题
时间: 2024-05-19 20:13:38 浏览: 55
是经典的寻找两个有序数组的中位数问题,可以使用二分查找来解决。
首先,我们可以将问题转化为寻找第 k 小的数,其中 k 为两个数组的长度之和除以 2,即 k = (m+n) // 2。如果 m+n 为奇数,则中位数为第 k 小的数;如果 m+n 为偶数,则中位数为第 k 小的数和第 k+1 小的数的平均值。
假设我们要寻找第 k 小的数,我们可以分别在 nums1 和 nums2 中查找第 k//2 小的数,比较它们的大小。如果 nums1[k//2-1] < nums2[k//2-1],那么 nums1 中的前 k//2 个数一定在前 k 小的数中,可以把它们全部排除。因为我们要找的是第 k 小的数,所以我们只需要在剩余的 nums1 和 nums2 数组中寻找第 k-k//2 小的数即可。如果 nums1[k//2-1] > nums2[k//2-1],同理可以排除 nums2 中的前 k//2 个数。如果 nums1[k//2-1] == nums2[k//2-1],那么这个数就是第 k 小的数。
具体实现时,我们需要考虑边界问题。如果有一个数组为空,则直接返回另一个数组的第 k 小的数。如果 k=1,则返回两个数组的第一个数中较小的那个。如果 nums1 或 nums2 的长度不足 k//2,则直接返回另一个数组中的第 k-k//2 小的数。
代码如下:
相关问题
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
解法一:暴力合并排序
将两个数组合并成一个有序数组,然后根据数组长度的奇偶性返回中位数。
时间复杂度: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));
}
}
};
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请用python找出并返回这两个正序数组的中位数
可以使用归并排序的思想来合并这两个有序数组,然后找到中位数。
具体步骤如下:
1. 将两个数组合并成一个有序数组。
2. 如果数组长度为奇数,中位数为数组中间的元素。
3. 如果数组长度为偶数,中位数为中间两个元素的平均值。
代码如下:
```python
def findMedianSortedArrays(nums1, nums2):
# 合并两个有序数组
nums = []
i, j = 0, 0
while i < len(nums1) and j < len(nums2):
if nums1[i] < nums2[j]:
nums.append(nums1[i])
i += 1
else:
nums.append(nums2[j])
j += 1
if i < len(nums1):
nums.extend(nums1[i:])
if j < len(nums2):
nums.extend(nums2[j:])
# 计算中位数
n = len(nums)
if n % 2 == 0:
return (nums[n // 2 - 1] + nums[n // 2]) / 2
else:
return nums[n // 2]
```
测试代码如下:
```python
print(findMedianSortedArrays([1, 3], [2])) # 输出 2.0
print(findMedianSortedArrays([1, 2], [3, 4])) # 输出 2.5
```