leetcode题目连接
设给出的两个已从小到大排序的数组为nums1和nums2,size1=nums1.size(),size2=nums2.size()。
分析题目能够知道,要找到中位数,最好能从2个已排序数组中找到第k小的数字,后者是更具通常性的问题。算法
咱们固然能够先merge这两个已经排序的数组,而后直接返回合并后数组的第k个数字。时间复杂度为O(size1+size2)。可是这个时间复杂度超出了题目限制的O(log (size1+size2))。数组
合并两个数组太耗时了,咱们不能这样作。
咱们的思路是,不断删掉数组中确定不是第k小的那些数字,从而可以不断地减少数组,在这个过程当中,咱们要找的那个数字的序号(k)也会不断地减少。
数组中的哪些数字能够删除呢?
让咱们假设k是4:
nums1: [a1, a2, a3, ...]
nums2: [b1, b2, b3, ...]
若是a2<b2,那么a2确定能够删除。由于有可能比a2小的数字只有:函数
所以,a2最多只能是第3小的数字,确定比咱们要找的第4数字要小!从而a2,以及比a2还小的a1,均可以删除。code
删除这两个数字之后,问题变成了:
nums1: [a3, ...]
nums2: [b1, b2, b3, ...]
从以上两个已排序数组中找出第2小的数字。(k已经变了,由于咱们已经删除了两个比咱们要找的那个数字还小的数字。)排序
同理,咱们能够删除a3和b1中较小的那个数字,而后问题变成从剩余数字中找到第1小的数字。这个问题不就简单了吗?递归
推广以上方法,咱们能够写出一个get_kth_smallest
函数:ip
class Solution { public: // findMedianSortedArrays只是简单地调用get_kth_smallest。后者才是算法的核心。 double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { int total_size = nums1.size()+nums2.size(); if (0 == total_size) throw std::invalid_argument( "received empty arrays" ); if (total_size%2 == 0) { return (get_kth_smallest(nums1, nums2, total_size/2)+get_kth_smallest(nums1, nums2, total_size/2+1))/2.0; } else { return get_kth_smallest(nums1, nums2, total_size/2+1); } } int get_kth_smallest(vector<int> nums1, vector<int> nums2, int k) { // 保证nums1.size() <= nums2.size(),方便分析 if (nums1.size() > nums2.size()) return get_kth_smallest(nums2, nums1, k); if (nums1.empty()) return nums2[k-1]; if (1 == k) return nums1[0] < nums2[0]? nums1[0]:nums2[0]; // 在nums1和nums2中分别取第k/2个数字。固然,若是k/2已经超出数组边界,咱们只取数组最后的那个数字。 int k1 = min(static_cast<int>(nums1.size()), k/2); int k2 = min(static_cast<int>(nums2.size()), k/2); if (nums1[k1-1] < nums2[k2-1]) { // 若是nums1[k1-1] < nums2[k2-1],说明nums1[k1-1]小于咱们要找的第k小的数字。 nums1.erase(nums1.begin(), nums1.begin()+k1); return get_kth_smallest(nums1, nums2, k-k1); } else { // 若是nums1[k1-1] > nums2[k2-1],说明nums2[k2-1]小于咱们要找的第k小的数字。 // 若是nums1[k1-1] == nums2[k2-1],说明nums2[k2-1]小于或等于咱们要找的第k小的数字。即便nums2[k2-1]等于咱们要找的第k小的数字,咱们依然能够删掉它,由于还有nums1[k1-1]和它相等呢! nums2.erase(nums2.begin(), nums2.begin()+k2); return get_kth_smallest(nums1, nums2, k-k2); } } };
注意到get_kth_smallest中没有循环语句,只有递归,所以时间复杂度彻底取决于get_kth_smallest
的调用次数。leetcode
get_kth_smallest
都会使k减少一半。k减少为1时获得结果。从而时间复杂度为O(log_2(k))。由于k<size1+size2,因此时间复杂度符合题目要求。