題目描述:
這題還是有點難度的,想了比較久,最開始的時候沒看見複雜度要求,心想不就是把兩個數組合並起來就可以了麼,爲什麼tag是困難,結果看見複雜度要求,才知道要二分做,一開始二分又想錯了方向,嘗試建立兩個數組各自的中位數的聯繫,結果寫了一大堆發現自己走錯了路,最後參考別人的思路才做出。
解題思路:本題核心函數就一個: double findKth(vector<int> &nums1, int i, vector<int> &nums2, int j, int k)
表示找到兩個排序數組最後合併排序後的第k個數,其中 int i和int j表示還沒搜索過的元素的起點(比如初始的時候i和j都等於0)
那麼怎麼在沒有合併的情況下,怎麼找到第k個數呢?
思路是這樣的:判斷 nums1 數組中第k/2個數 和 nums2 數組中第k/2個數的大小關係,比如 nums1[k/2-1] < nums2[k/2-1],那麼第k個數肯定不在nums1[0] 到 nums1[k/2-1]這個區間內,因此,直接把nums1[0] 到 nums1[k/2-1]這個區間排除,在對剩下元素的遞歸處理。這樣說可能有點抽象,舉個具體的例子來說明下。
比如:nums1 裏面有 10 個元素,nums2裏面也有 10 個元素,現在問題要求第16個元素是多少( k = 16)?
首先,k/2 = 8 ,找到nums1中第8個元素nums1[7],和nums2中第k - k/2 = 8個元素nums2[7],如果nums1[7]<nums2[7],那麼答案肯定不在nums1[0]到num1[7]之間,因爲即使最壞的情況,nums2[0]到nums2[6]全在nums1[0]到nums1[7]裏面,那麼這裏面一共也才15個元素 < (k = 16),所以直接把nums1[0]到nums1[7] 排除掉,對剩下的elems遞歸處理。
本題的核心算法就是上面一段,還有個難點就是關於座標的換算,我主要就是卡在了這個地方,具體看以下代碼,可以結合上一段舉的例子來理解:
class Solution {
public:
/**
* @param A: An integer array.
* @param B: An integer array.
* @return: a double whose format is *.5 or *.0
*/
double findMedianSortedArrays(vector<int> A, vector<int> B) {
// write your code here
int sizeA = A.size(), sizeB = B.size();
if (sizeA <= 0 && sizeB <= 0) {
return 0;
}
int total = sizeA + sizeB;
if (total % 2 == 1) {
return findKth(A, 0, B, 0, total / 2 + 1);
}
else {//偶數則取中間兩個值的平均數
return (findKth(A, 0, B, 0, total / 2) + findKth(A, 0, B, 0, total / 2 + 1)) / 2;
}
}
double findKth(vector<int> &nums1, int i, vector<int> &nums2, int j, int k) {
//一定要保證nums1的長度小於nums2的長度,不然對nums2的訪問可能會越界
if (nums1.size() - i > nums2.size() - j) {
return findKth(nums2, j, nums1, i, k);
}
// 判斷小的數組是否爲空,爲空的話,直接在另一個數組找第K個即可
if (nums1.size() == i) {//遞歸結束情況1
return nums2[j + k - 1];
}
// 當K = 1時,表示我們要找第一個元素,只要比較兩個數組的第一個元素,返回較小的那個即可
if (k == 1) {//遞歸結束情況2
return min(nums1[i], nums2[j]);
}
//pa表示在nums1中定位的元素的座標加上一(下面訪問的時候會減掉),pb同理
int pa = min(i + k / 2, int(nums1.size())), pb = j + k - (pa - i);//nums1中的元素不夠k/2的話,那麼就有多少取多少(nums1.size()) //pa - i :在nums1中已取得元素的個數 //k - (pa - i):剩下的還需要在nums2中取得元素的個數
if (nums1[pa - 1] < nums2[pb - 1]) {
return findKth(nums1, pa, nums2, j, k - pa + i);
}
else if (nums1[pa - 1] > nums2[pb - 1]) {
return findKth(nums1, i, nums2, pb, k - pb + j);
}
else {
return nums1[pa - 1];//相等的話說明說明這就是答案,直接返回即可
}
}
};
還有爲什麼要二分呢,其實你nums1中取k/3個,nums2中取2k/3個,然後比較nums1[k/3-1]和nums2[2k/3-1]也可以,因爲明顯二分最快。