原题为:算法
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)).数组
好吧,我是普通青年,第一反应就是使用Merge两个数字的思想,直接找到中位数。可是这个算法的复杂度是O(m+n)。ide
leetcode给这道题打上的标签是divide and conquer以及binary search。其实我以为这个标签有点误导性。百思不得其解以后看了关于这道题的discussion,看完以后不由感叹:我数学没学好。编码
这道题的解题思路是这样子的:code
该方法的核心是将原问题转变成一个寻找第k小数的问题(假设两个原序列升序排列),这样中位数其实是第(m+n)/2小的数。因此只要解决了第k小数的问题,原问题也得以解决。递归
首先假设数组A和B的元素个数都大于k/2,咱们比较A[k/2-1]和B[k/2-1]两个元素,这两个元素分别表示A的第k/2小的元素和B的第k/2小的元素。这两个元素比较共有三种状况:>、<和=。若是A[k/2-1]<B[k/2-1],这表示A[0]到A[k/2-1]的元素都在A和B合并以后的前k小的元素中。换句话说,A[k/2-1]不可能大于两数组合并以后的第k小值,因此咱们能够将其抛弃。而后在两个数组剩下的元素里寻找第k-(k/2)大的元素(经过递归的方式)。leetcode
当A[k/2-1]>B[k/2-1]时存在相似的结论。数学
当A[k/2-1]=B[k/2-1]时,咱们已经找到了第k小的数,也即这个相等的元素,咱们将其记为m。因为在A和B中分别有k/2-1个元素小于m,因此m便是第k小的数。(这里可能有人会有疑问,若是k为奇数,则m不是中位数。这里是进行了理想化考虑,在实际代码中略有不一样,是先求k/2,而后利用k-k/2得到另外一个数。)it
如何证实以上的规律是数学书里的内容,这里不作太多介绍。io
在实际的编码过程当中,咱们须要考虑以下边界条件:
1. 若是m或者n为0,直接返回A[k-1]或者B[k-1];
2. 若是k为1,那么返回A[0]或者B[0]当中较小的一个;
3. 若是A[k/2-1] == B[k/2-1],那么直接返回两个数中的任何一个。
代码以下:
class Solution { public: double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { int m = nums1.size(); int n = nums2.size(); //cout << m << " " << n << endl; if ((m+n)%2 == 0) { //cout << "even" << endl; return (findKthNum(nums1, nums2, (m + n) / 2) + findKthNum(nums1, nums2, (m + n) / 2 + 1))/2; } else { //cout << "odd" << endl; return findKthNum(nums1, nums2, (m + n) / 2 + 1); } } int min(int a, int b) { if (a < b) { return a; } else { return b; } } double findKthNum(vector<int>& nums1, vector<int>& nums2, int k) { if (nums1.size() > nums2.size()) { return findKthNum(nums2, nums1, k); //注意nums1的size必定要比nums2小,否则会发生溢出错误 } //当m或者n为0时 if (nums1.size() == 0) { if (k <= nums2.size()) { return nums2[k - 1]; } else { return nums2[nums2.size() - 1]; } } else if (nums2.size() == 0) { if (k <= nums1.size()) { return nums1[k - 1]; } else { return nums1[nums1.size() - 1]; } } if (k == 1) { return min(nums1[0], nums2[0]); } int offset_1 = min(k / 2, nums1.size()); int offset_2 = k - offset_1; vector<int> new_nums1, new_nums2; int i = 0; if (nums1[offset_1-1] == nums2[offset_2-1]) { return nums1[offset_1-1]; } else if (nums1[offset_1-1] < nums2[offset_2-1]) { for (vector<int>::iterator it = nums1.begin(); it != nums1.end(); it++) { if (i >= offset_1) { new_nums1.push_back(*it); } i++; } return findKthNum(new_nums1, nums2, k - offset_1); } else { for (vector<int>::iterator it = nums2.begin(); it != nums2.end(); it++) { if (i >= offset_2) { new_nums2.push_back(*it); } i++; } return findKthNum(nums1, new_nums2, k - offset_2); } } };