又是得空的一天开始打卡
感冒依旧没好,继续打卡!
题目描述
题目意思很简单,就是从两个已经排好序的数组中,找出中位数,中位数的意思想必小学都已经学过了。本身题目很简单,但是题目要求的时间复杂度却是一个难点,当然很明显,要实现如此复杂度,二分法很合适!
解法
- 暴力解法
这个方法很佛系,虽然不满足题目的复杂度O(log(m+n))但是依旧提交成功,并且耗时也不多,虽然没有双百…
(1)代码
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int count = nums1.size()+nums2.size();
int i =0;
int j=0;
int foreNum=0;
int nowNum=0;
int num=0;
int s1 =i< nums1.size()?nums1.at(i):numeric_limits<int>::max();
int s2 = j < nums2.size()?nums2.at(j):numeric_limits<int>::max();
while(true){
foreNum = nowNum;
if(s1 > s2 ){
nowNum = s2;
s2 = j < nums2.size()-1?nums2.at(++j):numeric_limits<int>::max();
}
else{
nowNum = s1;
s1 = i< nums1.size()-1?nums1.at(++i):numeric_limits<int>::max();
}
if(num == count /2){
return count%2==0?(foreNum+nowNum)/2.0:nowNum;
}
num++;
}
}
时间复杂度大概应该是O((m+n)/2),思路很简单,就是单纯的将两个集合里的数一个个取出,然后比较,按从小到大的顺序,当到达中位数的位置时,输出结果。
(2)结果:
虽然没有双百,但是暴力解法能到这样我已经很满足了!
- 二分法
根据题目要求的时间复杂度,看到的第一想法应该就是用二分法(排除那些明显不可能的结果,就如剪枝)来做,思考了一下(顺便借鉴了点前人的经验),废话不多说先上代码,如下:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int count = nums1.size() + nums2.size();
if (count % 2 == 1) {
return getKthElement(nums1, nums2, (count + 1) / 2);
}
else {
return (getKthElement(nums1, nums2, count / 2) + getKthElement(nums1, nums2, count / 2 + 1)) / 2.0;
}
}
//找第k小
int getKthElement(const vector<int>& nums1, const vector<int>& nums2, int k) {
int m = nums1.size();
int n = nums2.size();
int index1 = 0, index2 = 0;
while (true) {
// 边界情况
if (index1 == m) {
return nums2[index2 + k - 1];
}
if (index2 == n) {
return nums1[index1 + k - 1];
}
if (k == 1) {
return min(nums1[index1], nums2[index2]);
}
// 正常情况
int newIndex1 = min(index1 + k / 2 - 1, m - 1);
int newIndex2 = min(index2 + k / 2 - 1, n - 1);
int pivot1 = nums1[newIndex1];
int pivot2 = nums2[newIndex2];
if (pivot1 <= pivot2) {
k -= newIndex1 - index1 + 1;
index1 = newIndex1 + 1;
}
else {
k -= newIndex2 - index2 + 1;
index2 = newIndex2 + 1;
}
}
}
解释(总结了一下经验,这部分并非原创):
假设两个有序数组分别是 A 和 B。要找到第 k 个元素,我们可以比较 A[k/2−1] 和 B[k/2−1],其中 // 表示整数除法。由于 A[k/2−1] 和B[k/2−1] 的前面分别有 A[0…k/2−2] 和 B[0…k/2−2],即k/2−1 个元素,对于A[k/2−1] 和 B[k/2−1] 中的较小值,最多只会有 k/2-1+(k/2−1)≤k−2 个元素比它小,那么它就不能是第 k 小的数了。
因此我们可以归纳出三种情况:
(1)如果 A[k/2−1]<B[k/2−1],则比 A[k/2−1] 小的数最多只有 A 的前 k/2−1 个数和 B 的前k/2−1 个数,即比A[k/2−1] 小的数最多只有 k−2 个,因此 A[k/2−1] 不可能是第 k 个数,A[0] 到A[k/2−1] 也都不可能是第 k 个数,可以全部排除。
(2)如果 A[k/2−1]>B[k/2−1],则可以排除 B[0] 到 B[k/2−1]。
(3)如果 A[k/2−1]=B[k/2−1],则可以归入第一种情况处理。
那么就可以根据这个方法实现O(log(m+n))的时间复杂度。
附上原解:二分法寻找两个正序数组的中位数
运行结果如下:
其实相对来说,系统所用的测试数组并不太大,表现出的时间复杂度区别不太大,但仍很快!!!
这个方法相对来说,我用的并不多,看来还是得再熟练熟练,多练几次。
今天这个题比较难,自己近九点才开始写(下次一定要在七点半就开始写),所以就只写了一个题目!!!
睡觉睡觉!!!
明天好好把握时间!!!