4. 寻找两个正序数组的中位数
题目描述
给定两个大小分别为
m和n的正序(从小到大)数组nums1和nums2。请你找出并返回这两个正序数组的 中位数 。
解题思路
有序数组中找中位数,其实就是找特定下标的元素。
简单的思路是先将两个有序数组归并,归并后总元素数量为 m+n ,
- 若总元素数目为奇数,则寻找下标为
(m+n)/2的元素 - 若元素为偶数,则寻找下标为
(m+n)/2-1和(m+n)/2的元素,取平均
该思路的时间复杂度为 O(m+n) 。
如果省去归并操作,直接使用二分法来寻找特定的元素,那么就可以把事件复杂度降至 O(log(m+n)) 。
这种思路的关键在于设计二分法的策略。首先,“两个正序数组中寻找中位数”可以转化为“两个正序数组中寻找第k大的数”,然后,使用排除法,一点一点地去掉第1~k-1大的数。
二分法的循环体
比较 nums1[k/2 - 1] 和 nums2[k/2 - 1] ,如果 nums1[k/2 - 1] <= nums2[k/2 - 1] :
nums2[k/2 - 1] >= nums1[k/2 - 1] >= ... >= nums1[0],排除掉k/2个元素
在下一轮循环中,nums1[0] 、nums1[1] 、…、nums1[k/2 - 1] 被排除,并且 k -= k/2 。
二分法的边界条件
- 如果某数组为空,那么返回另一个数组第k大的数
- 如果
k=1,那么返回两数组首元素中较小的数
二分法的特殊情况
每轮循环中,我们设置的下标 index + k/2 - 1 可能越界,此时需要把二分法更新迭代的步长设为0。
复杂度分析
时间复杂度:O(log(m+n))
空间复杂度:O(1)
知识点
二分法、中位数
代码
class Solution {public:double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {int size1 = nums1.size();int size2 = nums2.size();if ((size1 + size2) % 2 == 1) {return findKthElement(nums1, nums2, (size1 + size2)/2 + 1);} else {cout << findKthElement(nums1, nums2, (size1 + size2)/2) << endl;cout << findKthElement(nums1, nums2, (size1 + size2)/2 + 1) << endl;return (findKthElement(nums1, nums2, (size1 + size2)/2)+ findKthElement(nums1, nums2, (size1 + size2)/2 + 1)) / 2.0;}}double findKthElement(vector<int>& nums1, vector<int>& nums2, int k) {int begIndex1 = 0;int begIndex2 = 0;int size1 = nums1.size();int size2 = nums2.size();int step1 = k/2 - 1;int step2 = k/2 - 1;while (true) {if (size1 - begIndex1 == 0) {return nums2[begIndex2 + k - 1];} else if (size2 - begIndex2 == 0) {return nums1[begIndex1 + k - 1];} else if (k == 1) {return min(nums1[begIndex1], nums2[begIndex2]);} else if (begIndex1 + step1 >= size1) {step1 = 0;} else if (begIndex2 + step2 >= size2) {step2 = 0;}if (nums1[begIndex1 + step1] <= nums2[begIndex2 + step2]) {begIndex1 += step1 + 1;// begIndex2 += step2;k -= step1 + 1;} else {// begIndex1 += step1;begIndex2 += step2 + 1;k -= step2 + 1;}step1 = k/2 - 1;step2 = k/2 - 1;// cout << "begIndex1: " << begIndex1 << endl;// cout << "begIndex2: " << begIndex2 << endl;// cout << "k: " << k << endl;}}};
