我觉得这是目前hot里最难的题了,不敢想象面试碰到这等恐怖的题会是怎样一番腥风血雨。
大体思路其实不难(找到正确方法途径实现还是有难度的),难点主要集中在情况巨多,但凡这题给定两数组长度之和一定为奇数都不会这么难。
思路想了好一会,我先是想到每次取两数组的中间值比较,将大的那个后面的元素全部剔除,但这种方法需要记录原始数组长度、剔除的长度,每次都要比较是否剔除了一半的原长度……
看来答案才发现可以从前往后剔除,思路其实差不多但是实现起来答案确实更简单。
我最终的方法结合了答案和自己的想法:先记录需要找的位置k=(nums1.size()+nums2.size()-1)/2,同样是每次找寻中间节点k/2比较,剔除中间值小的那个数组的右边部分,k减去剔除的值,每个循环检查k,若k为0则取两数组首位更小的那个值。
这还只是大体思路,还有很多其余情况,比如一个数组的长度达不到k/2,这时候就取这个数组的最后一个元素和另一个数组中间点比较;还有一个数组已经为空,这时候取另一个数组的第k个位置即可;还有需要加入bool判断有几个中位数,如果有两个就还要取下一个最小值与当前最小值相加除以二……
总之最终还是“顺利”的过了。
class Solution {
public:double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {bool b=(nums1.size()+nums2.size())%2;int k=(nums1.size()+nums2.size()-1)/2;while(1){if(nums1.size()==0){if(b==1) return nums2[k];else return static_cast<double>(nums2[k]+nums2[k+1])/2;}if(nums2.size()==0){if(b==1) return nums1[k];else return static_cast<double>(nums1[k]+nums1[k+1])/2;}if(k==0){if(b==1) return min(nums1[0],nums2[0]);else if(nums2.size()>1&&nums1[0]>nums2[0]) return static_cast<double>(nums2[0]+min(nums1[0],nums2[1]))/2;else if(nums1.size()>1&&nums1[0]<nums2[0]) return static_cast<double>(nums1[0]+min(nums1[1],nums2[0]))/2;else return static_cast<double>(nums1[0]+nums2[0])/2;}if(nums1.size()<=k/2){if(nums1[nums1.size()-1]>nums2[k/2]){nums2.erase(nums2.begin(),nums2.begin()+(k+1)/2);k-=(k+1)/2;}else{k-=nums1.size();nums1.clear();}}else if(nums2.size()<=k/2){if(nums2[nums2.size()-1]>nums1[k/2]){nums1.erase(nums1.begin(),nums1.begin()+(k+1)/2);k-=(k+1)/2;}else{k-=nums2.size();nums2.clear();}}else if(nums1[k/2]>nums2[k/2]){nums2.erase(nums2.begin(),nums2.begin()+(k+1)/2);k-=(k+1)/2;}else{nums1.erase(nums1.begin(),nums1.begin()+(k+1)/2);k-=(k+1)/2;}}return 0;}
};
前三个if都是判断是否可以return了,后面的一系列if else都是移动k和删除元素。