leetcode.5 尋找兩個正序數組的中位數

4. 尋找兩個正序數組的中位數

給定兩個大小爲 m 和 n 的正序(從小到大)數組 nums1 和 nums2

請你找出這兩個正序數組的中位數,並且要求算法的時間複雜度爲 O(log(m + n))。

你可以假設 nums1 和 nums2 不會同時爲空。

 

示例 1:

nums1 = [1, 3]
nums2 = [2]

則中位數是 2.0

示例 2:

nums1 = [1, 2]
nums2 = [3, 4]

則中位數是 (2 + 3)/2 = 2.5

首先想到的算法是一個i掃描nums1, 一個j掃描nums2, 兩面總共掃描(m + n)/ 2次就好

但那個算法複雜度是 O(m + n)的

再看題目要求是O(log(m + n)), 一定是二分遞規

 

這裏我們定義一個遞歸函數來求兩個數組的第k個元素

如果k = 1, 那麼肯定是兩個數組的第一個數中的較小的那個

其他情況呢

兩個數組都找第 k / 2 個元素

如果某一個數組長度小於 k / 2 , 那第k個元素肯定在另一個數組中

比較兩個數組的第 k / 2 個元素,較小的那個的數組前 k / 2個元素中是肯定找不到了

然後在他剩下的部分和另一個數組中找第k - k / 2 個元素

這樣就二分遞歸找到了兩個數組的第k個數

 

還有一個問題,就是奇數個元素的中位數和偶數個元素的中位數的不同

這裏偷個懶

不管奇數偶數個元素,中位數都等於(第(m + n  + 1)/ 2個元素 + 第(m  + n + 2)/ 2個元素 ) / 2

#include <iostream>
#include <vector>
#include <float.h>

using namespace std;

double findk(vector<int>& nums1, int i, vector<int>& nums2, int j, int k){
	if(i >= nums1.size()){
		return nums2[j + k - 1];
	}
	if(j >= nums2.size()){
		return nums1[i + k - 1];
	}

	if(k == 1){
		if(nums1[i] < nums2[j]){
			return nums1[i];
		}
		else{
			return nums2[j];
		}
	}

	int mid1 = INT_MAX;
	int mid2 = INT_MAX;
	if(i + k/2 - 1 < nums1.size()){
		mid1 = nums1[i + k/2 - 1];
	}
	if(j + k/2 - 1 < nums2.size()){
		mid2 = nums2[j + k/2 - 1];
	}
	if(mid1 < mid2){
		return findk(nums1, i + k / 2, nums2, j, k - k / 2);
	}
	else{
		return findk(nums1, i, nums2, j + k / 2, k - k / 2);
	}


}


double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
    int m = nums1.size();
    int n = nums2.size();
    int l = (m + n + 1) / 2;
    int r = (m + n + 2) / 2;

    return (findk(nums1, 0, nums2, 0, l) + findk(nums1, 0, nums2, 0, r)) / 2;

}


int main(){
	int n1[] = {1, 3};
	int n2[] = {2};
	vector<int> nums1(n1, n1 + 2);
	vector<int> nums2(n2, n2 + 1);

	double re = findMedianSortedArrays(nums1, nums2);
	cout << re << endl;
	return 0;
}    




 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章