看到Ologn直接想二分;
这个二分查找不同于查中间值,而是更像是进行部分排除;
对于奇数或者偶数有序序列,查找中位数,相当于查找第k个值;
对于奇数个个数,相当于查找第(n+1)/2个值,而对于偶数个个数,相当于查找第n/2和n/2+1个数字,注意一下,这里下标都是从1开始计数;
对于查找第k个数字,则采用对半查询进行排除;
对于两个序列,分别为m,n大小,并且各自有序;
假设起始坐标都为0,则计算k/2-1,则两个序列的对比范围为: [ 0 , k / 2 − 1 ] [0,k/2-1] [0,k/2−1];
若 n u m 1 [ k / 2 − 1 ] > n u m 2 [ k / 2 − 1 ] num1[k/2-1]>num2[k/2-1] num1[k/2−1]>num2[k/2−1],则说明num2的前k/2个元素全部小于 n u m 1 [ k / 2 − 1 ] num1[k/2-1] num1[k/2−1],因此可以将这部分排除;
此时相当于从剩余的部分中寻找第 k − k / 2 k-k/2 k−k/2个数,循环至k=1;
之所以循环到k=1,是因为k/2-1=0,此时只需要从两个有序序列的标记索引中二选一即可;
需要注意的地方:
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int total = nums1.size() + nums2.size();
if (total % 2 == 1) {
return fun(nums1, nums2, (total + 1) / 2);
}
else {
return (fun(nums1, nums2, total / 2) + fun(nums1, nums2, total / 2 + 1))/2.0;
}
}
double fun(vector<int>& nums1, vector<int>& nums2, int k) {
int m = nums1.size();
int n = nums2.size();
int index1 = 0, index2 = 0;
while (1) {
if (m == index1) {
return nums2[index2 + k - 1];
}
if (n == index2) {
return nums1[index1 + k - 1];
}
if (k == 1) {
return min(nums1[index1], nums2[index2]);
}
int newindex1 = min(m - 1, index1 + k / 2 - 1);
int newindex2 = min(n - 1, index2 + k / 2 - 1);
if (nums1[newindex1] <= nums2[newindex2]) {
k -= newindex1 - index1 + 1;
index1 = newindex1 + 1;
}
else {
k -= newindex2 - index2 + 1;
index2 = newindex2 + 1;
}
}
}
};