[LeetCode]4. Median of Two Sorted Arrays两个排序数组合并后的中位数
There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
解法一:不考虑时间复杂度限制在O(log(m+n)),则将两个数组遍历一遍即可以组合成一个排好序的数组,然后取数组的中位数即可,时间复杂度O(m+n):
class Solution { public: double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { int m = nums1.size(); int n = nums2.size(); vector<int> vi(m + n, 0); int i = 0; int j = 0; int k = 0; if(m == 0) { if(n == 0) return 0; else return (n % 2 == 0) ? (nums2[n / 2 - 1] + nums2[n / 2]) / 2.0 : nums2[n / 2]; } if(n == 0) { if(m == 0) return 0; else return (m % 2 == 0) ? (nums1[m / 2 - 1] + nums1[m / 2]) / 2.0 : nums1[m / 2]; } if(m + n == 1) return (m == 1) ? nums1[0] : nums2[0]; for(int i = 0; i < m;) { if(j < n && nums1[i] > nums2[j]) { vi[k] = nums2[j]; j++; k++; } else { vi[k] = nums1[i]; i++; k++; } } while(j < n) { vi[k] = nums2[j]; j++; k++; } if((m + n) % 2 == 0) return (vi[(m + n) / 2 - 1] + vi[(m + n) / 2]) / 2.0; else return vi[(m + n) / 2]; } };
解法二:考虑时间复杂度要在O(log(m+n)),则不能简单的从头至尾遍历两个数组。因为数组都是排序的,一种自然地想法即是考虑二分查找。找到两个排序数组的中位数的一个延伸问题是找到两个排序数组的第K大元素,中位数是K=(m+n)/2的情况。可以这样考虑:先分别找到两个排序数组的第K大元素进行比较,即比较arr1[k/2-1]和arr2[k/2-1]的大小,假设arr1[k/2-1]>arr2[k/2-1],则显而易见arr2中排在arr2[k/2-1]之前的元素不可能是合并后排序数组的中位数,因为arr2[k/2-1]不可能大于合并后数组的第K大值,而arr2[0]到arr2[k/2-2]均小于arr2[k/2-1],则更不可能是合并后数组的第K大值了,因此这部分可以丢弃;然后再对一个旧的排序数组和一个新的排序数组递归调用上述过程,最后即可得到合并后排序数组的第K个数。
需要注意的是需要针对数组长度小于K/2的情况单独考虑。
class Solution { public: double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { int m = nums1.size(); int n = nums2.size(); int t = m + n; if (m == 0 || n == 0) { if (m == 0 && n == 0) return -1; if (m == 0 && n > 1) { if (n % 2 == 0) return (nums2[n / 2 - 1] + nums2[n / 2]) / 2.0; else return nums2[n / 2]; } if (n == 0 && m > 1) { if (m % 2 == 0) return (nums1[m / 2 - 1] + nums1[m / 2]) / 2.0; else return nums1[m / 2]; } } if (t == 1) return (m == 0) ? nums2[0] : nums1[0]; if (t == 2) return (nums1[0] + nums2[0]) / 2.0; if (t % 2 == 0) return (findKth(nums1, m, nums2, n, t / 2) + findKth(nums1, m, nums2, n, t / 2 + 1)) / 2.0; else return findKth(nums1, m, nums2, n, t / 2 + 1); } private: double findKth(vector<int> a, int as, vector<int> b, int bs, int k) { if (as > bs) return findKth(b, bs, a, as, k); if (k <= 0) return -1; if (as == 0 || bs == 0) { if (as == 0 && bs == 0) return -1; if (as == 0) return b[k - 1]; if (bs == 0) return a[k - 1]; } if (k == 1) return a[0] > b[0] ? b[0] : a[0]; int pa = k / 2 > as ? as : k / 2; int pb = k - pa; if (a[pa - 1] > b[pb - 1]) return findKth(a, as, vector<int>(b.begin() + pb, b.end()), bs - pb, k - pb); else if (a[pa - 1] < b[pb - 1]) return findKth(vector<int>(a.begin() + pa, a.end()), as - pa, b, bs, k - pa); else return a[pa - 1]; } };