题目描述
题目链接
给定两个大小为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的中位数。
示例 1:
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:
输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
示例 3:
输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000
示例 4:
输入:nums1 = [], nums2 = [1]
输出:1.00000
示例 5:
输入:nums1 = [2], nums2 = []
输出:2.00000
自己做题时的想法
将两个vector合并到一起+sort+返回新序列的中位数
Emmm…虽然可以过 但是没有达到题目的另一个要求 时间复杂度控制在O(log(m+n))
但是 这个做法的时间复杂度取决于排序 即O((m+n)log(m+n))
【m为第一个序列的长度 n为第二个序列的长度】
观摩了官方解答后
自己的理解
一般题目要求log的复杂度 就大概率要用到二分查找了
回到这个题目 题目求中位数
那么肯定要分为两类
-
第一类 m+n为奇数
此时中位数为有序序列的第(m+n+1)/2个元素 -
第二类 m+n为偶数
此时中位数为有序序列的第(m+n)/2和第(m+n)/2+1个元素的平均值
转化成求两个有序序列中第k小的元素
假设两个有序数组分别是A和B 要找到第K个元素 即可转化为比较A[k/2-1]和B[k/2-1]中的较小值 对于这个求出的较小值 它最多只可能是第k-1个元素 不会是第k个元素 因此可以排除在外
分成两种情况讨论
- 若A[k/2-1]<=B[k/2-1] 此时A[k/2-1]最多只可能是第k-2个数 所以排除A[0]到A[k/2-1]
- 若A[k/2-1]>B[k/2-1] 此时同理 排除B[0]到B[k/2-1]
在每次这种比较后,都可以排除k/2个元素,此时搜索范围减小一半,然后再在新的数组上进行新一轮的二分查找
边界处理
- 如果A[k/2-1] or B[k/2-1]越界 则取其对应数组的最后一个元素 此时需要根据已经排除的元素个数更新k
- 如果一个数组为空 则直接返回另一个序列中第k个元素
- 如果k==1 则返回两个序列首元素中的最小值
code
class Solution {
public:
int getKthElement(const vector<int>& v1, const vector<int>& v2, int k) {
int m = v1.size();
int n = v2.size();
int index1 = 0, index2 = 0;
while (true) {
if (index1 == m)return v2[index2 + k - 1];
if (index2 == n)return v1[index1 + k - 1];
if (k == 1)return min(v1[index1], v2[index2]);
int newIndex1 = index1 + k / 2 - 1;
int newIndex2 = index2 + k / 2 - 1;
int p1 = v1[newIndex1];
int p2 = v2[newIndex2];
if (p1 <= p2) {
k -= newIndex1 - index1 + 1;
index1 = newIndex1 + 1;
}
else {
k -= newIndex2 - index2 + 1;
index2 = newIndex2 + 1;
}
}
}
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int sum = nums1.size() + nums2.size();
if (sum & 1) {
return getKthElement(nums1, nums2, (sum + 1) / 2);
}
else {
return (getKthElement(nums1, nums2, sum / 2) + getKthElement(nums1, nums2, sum / 2 + 1)) / 2.0;
}
}
};