寻找两个正序数组的中位数
给定两个大小分别为 m
和 n
的正序(从小到大)数组 nums1
和 nums2
。请你找出并返回这两个正序数组的 中位数 。算法的时间复杂度应该为 O(log (m+n))
。
方法一:(不推荐)
cpp
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
vector<int> merged;
double median = 0;
int i=0,j=0;
while(i < nums1.size() && j < nums2.size()){
if(nums1[i] < nums2[j]){
merged.push_back(nums1[i]);
i++;
} else {
merged.push_back(nums2[j]);
j++;
}
}
while (i < nums1.size()) {
merged.push_back(nums1[i]);
i++;
}
while(j < nums2.size()){
merged.push_back(nums2[j]);
j++;
}
int n = merged.size();
if (n % 2 == 0) {
median = (merged[n / 2 - 1] + merged[n / 2]) / 2.0;
} else {
median = merged[n / 2];
}
return median;
}
};
- 使用双指针
i
和j
分别指向nums1
和nums2
的起始位置。 - 比较
nums1[i]
和nums2[j]
,将较小的元素放入merged
数组。 - 将较小元素的指针后移(即,继续检查数组中的下一个元素)。
- 直到一个数组被完全遍历。
- 如果
nums1
还有剩余元素,将其直接追加到merged
中。 - 同样地,如果
nums2
还有剩余元素,也直接追加到merged
中。 - 这样,
merged
就是一个完整的、合并后的有序数组。 - 首先获取
merged
数组的大小n
。 - 如果
n
是偶数:- 中位数是数组中间两个数的平均值,即
(merged[n / 2 - 1] + merged[n / 2]) / 2.0
。
- 中位数是数组中间两个数的平均值,即
- 如果
n
是奇数:- 中位数是数组的中间元素,即
merged[n / 2]
。
- 中位数是数组的中间元素,即
方法二:
cpp
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
// 确保 nums1 是较短的数组
if (nums1.size() > nums2.size()) {
return findMedianSortedArrays(nums2, nums1);
}
int m = nums1.size();
int n = nums2.size();
int totalLeft = (m + n + 1) / 2;
int left = 0, right = m;
while (left < right) {
int i = left + (right - left) / 2;
int j = totalLeft - i;
if (nums1[i] < nums2[j - 1]) {
// i 需要右移
left = i + 1;
} else {
// i 需要左移
right = i;
}
}
int i = left;
int j = totalLeft - i;
// 左半部分的最大值
int nums1LeftMax = (i == 0) ? INT_MIN : nums1[i - 1];
int nums2LeftMax = (j == 0) ? INT_MIN : nums2[j - 1];
int leftMax = max(nums1LeftMax, nums2LeftMax);
// 如果总长度是奇数
if ((m + n) % 2 == 1) {
return leftMax;
}
// 右半部分的最小值
int nums1RightMin = (i == m) ? INT_MAX : nums1[i];
int nums2RightMin = (j == n) ? INT_MAX : nums2[j];
int rightMin = min(nums1RightMin, nums2RightMin);
// 如果总长度是偶数,返回平均值
return (leftMax + rightMin) / 2.0;
}
};
1. 确保 nums1 是较短的数组
通过判断 nums1
和 nums2
的长度,始终在较短的数组上进行二分查找。
2. 使用二分查找调整分割点
i
是在nums1
的分割点,j
是在nums2
的分割点。i + j = totalLeft
,保证左半部分元素总数等于右半部分。- 根据条件调整
i
:- 如果
nums1[i] < nums2[j - 1]
,说明i
需要右移。 - 如果
nums1[i] >= nums2[j - 1]
,说明i
满足条件或需要左移。
- 如果
3. 计算中位数
- 左半部分最大值为:
max(nums1[i-1], nums2[j-1])
。 - 右半部分最小值为:
min(nums1[i], nums2[j])
。 - 如果总长度为奇数,直接返回左半部分最大值。
- 如果总长度为偶数,返回左右半部分最大值与最小值的平均值。