一、題目描述
二、解題思路
題目要求時間複雜度爲,很明顯需要採用二分法來解決。
如果我們可以在這兩個有序序列中找到第個數字,那麼我們只要能找到中間的一個或兩個數字,就一定可以得到這道題的解。
所以問題退化爲尋找兩個有序序列的按序第個數字。
在尋找中間的數字的過程中,需要區分以下兩個序列長度和爲奇數偶數的區別:
- 如果爲奇數,那麼中間的數字只有一個,那就是第個位置的元素
- 如果是偶數,那麼中間的數字有兩個,分別第是和個元素
- 其實,奇數時,與的值是相等的;那麼就可以得出:
- 當奇數時,中位數就是按序排列後的第或個元素
- 當偶數時,中位數就是按序排列後的第或個元素的平均值
確定了結果所需數字的位置,便可開始根據這個位置在兩個有序數組中找到這個位置的工作,這裏採用一個輔助函數來完成。
- 如果起始位置大於等於數組長度,說明這個數組需要查找的部分已經變空,這個位置一定不可能在該數組裏,那麼直接返回另一個數組的第個位置
- 如果,那麼就直接返回兩個數組待查找部分兩個開頭元素的較小值
- 否則,對進行二分,需要比較兩個數組裏偏移待查起始位置處元素的大小,分別記爲和
- 如果,說明第一個數組劃分範圍過大,導致其偏移處的元素過小,需要縮小第一個數組的範圍到更大的部分,調整第一個數組的起始位置到後處
- 反之,需要調整第二個數組的起始位置到後處
- 調整的同時,還要縮小的範圍,這裏是把縮小到而不是,原因在於如果爲偶數還好辦,如果爲奇數的話,比如說,就會直接變成,但實際上我們知道應該是變成,這樣才滿足二分的定義,否則就過不去測試用例
[1, 2]; [3, 4]
三、解題代碼
class Solution {
private:
int findKth(vector<int>& num1, int start1, vector<int>& num2, int start2, int k){
if(start1 >= num1.size()) return num2[start2 + k - 1];
if(start2 >= num2.size()) return num1[start1 + k - 1];
if(k == 1) return min(num1[start1], num2[start2]);
int half1 = (start1 + k / 2 - 1) < num1.size() ? num1[start1 + k / 2 - 1] : INT_MAX;
int half2 = (start2 + k / 2 - 1) < num2.size() ? num2[start2 + k / 2 - 1] : INT_MAX;
return half1 < half2 ? findKth(num1, start1 + k / 2, num2, start2, k - k / 2) : findKth(num1, start1, num2, start2 + k / 2, k - k / 2);
}
public:
double findMedianSortedArrays(vector<int>& num1, vector<int>& num2) {
int len1 = num1.size();
int len2 = num2.size();
int left = (len1 + len2 + 1) / 2;
int right = (len1 + len2 + 2) / 2;
return (findKth(num1, 0, num2, 0, left) + findKth(num1, 0, num2, 0, right)) / 2.0;
}
};