在計算機科學中,分治法是建基於多項分支遞歸的一種很重要的算法範式。字面上的解釋是「分而治之」,就是把一個複雜的問題分紅兩個或更多的相同或類似的子問題,直到最後子問題能夠簡單的直接求解,原問題的解即子問題的解的合併。java
There are two sorted arrays nums1 and nums2 of size m and n respectively.算法
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).數組
You may assume nums1 and nums2 cannot be both empty.優化
Example 1:編碼
nums1 = [1, 3] nums2 = [2]spa
The median is 2.0 Example 2:設計
nums1 = [1, 2] nums2 = [3, 4]3d
The median is (2 + 3)/2 = 2.5指針
給定兩個大小爲 m 和 n 的有序數組 nums1 和 nums2。code
請你找出這兩個有序數組的中位數,而且要求算法的時間複雜度爲 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
根據題目要求,兩個有序數組尋找中位數,天然能夠聯想到最簡單的有序數組合並。可是合併有序數組尋找中位數顯然算法複雜度會超過題目要求的O(log(m + n)),不過根據題目的複雜度要求O(log(m + n))又能明顯的想到題解思路必然跟分而治之算法思想相關,由於只有分治法思想的算法複雜度才能達到log級別。
因爲本題是求中位數,題解必然屬於分治,可採用二分法。若要找出兩個數組全部數中的第k個數,能夠採用淘汰法,每次取兩個數組中的前k/2個數,比較兩個數組中第k/2個數得出較小的那一個,能夠淘汰掉較小數所在數組的k/2以前的全部數,接着獲得兩個新數組遞歸循環淘汰 最後直到累計找到第k個數。 舉例說明,假設有兩個數組m、n長度分別爲五、10。因爲是尋找中位數,所以數組之和len=5+10=15爲奇數,中位數正好是第8個數即k爲8。
第一次將A和B分別取前k/2 = 4個數,如上圖所示,因爲B數組中第4位數4小於A數組中第4位數11,所以淘汰B數組的前4位,同時得出新數組繼續比較。因爲此時總數已經捨棄4個得出新k爲8-4=4。
第二次將A和B分別取前k/2 = 2個數,如上圖所示,因爲A數組中第2位數4小於B數組中第2位數6,所以淘汰A數組的前2位,同時得出新數組繼續比較。因爲此時總數已經捨棄2個得出新k爲4-2=2。
第三次將A和B分別取前k/2 = 1個數,如上圖所示,因爲A數組中第1位數5等於B數組中第1位數5,所以仍淘汰A數組的前1位,此時k爲1結束二分,而且此時總數已經捨棄1個得出新k位2-1=1。
最後一次由於尋找的數字爲第8位,故只需對比新數組A、B的第一位得出較小的數便可。因爲數組B第1位數5小於數組A第1位數,所以5即是最終兩個數組的中位數。
1、求兩數組中位數(findMedianSortedArrays方法)
1、根據nums1數組長度len1和nums2數組長度len2獲得中位數k;
2、i.若兩數組總長爲奇數,此時只有一箇中位整數,直接調用方法二返回兩數組的第k位數;
ii.若兩數組總長爲偶數,此時有兩個中位整數,分別是第k和第k+1位,調用方法二傳入k、k+1計算2箇中位整數平均值得出中位數;
2、根據數組,起始位置,k值,求兩有序數組的第k位整數(numberK方法)
1、根據兩數組的起始位置和長度得出當前數組的有效長度len一、len2;
2、保證有效長度小的數組在前面;
3、特殊狀況處理,當len1爲0即第一個有效數組爲空時,直接返回第2個數組的第k位整數(相對起始位置);
4、特殊狀況處理,當兩數組均只有1個元素時直接返回較小的的整數;
5、根據起始位置、數組長度、k值分別計算兩個數組相對起始位置的第k個數的下標。注意當數組長度小於k時,特殊處理將下標移到數組最後一位;
6、對比兩數組第k個數的大小:
i.若第2個數組的第k個數較小,則移動第2個數組指針,相對於起始位置k位,至關於淘汰第2個數組的k個數,繼續遞歸調用;
ii.反之若第1個數組的第k個數較小,則移動第1個數指針,相對於起始位置k位,至關於淘汰第1個數組的k個數,繼續遞歸調用;
複製代碼
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int len1 = nums1.length;
int len2 = nums2.length;
int k = (len1 + len2 + 1) / 2;
if (((len1 + len2) & 1) == 1) {
return numberK(nums1, 0, nums2, 0, k);
} else {
return (numberK(nums1, 0, nums2, 0, k) + numberK(nums1, 0, nums2, 0, k + 1)) * 0.5;
}
}
private int numberK(int[] n1, int start1, int[] n2, int start2, int k) {
int len1 = n1.length - start1;
int len2 = n2.length - start2;
if (len1 > len2) {
return numberK(n2, start2, n1, start1, k);
}
if (len1 == 0) {
return n2[start2 + k - 1];
}
if (k == 1) {
return Math.min(n1[start1], n2[start2]);
}
int end1 = start1 + Math.min(len1, k / 2) - 1;
int end2 = start2 + Math.min(len2, k / 2) - 1;
if (n1[end1] > n2[end2]) {
return numberK(n1, start1, n2, end2 + 1, k - (end2 - start2 + 1));
} else {
return numberK(n1, end1 + 1, n2, start2, k - (end1 - start1 + 1));
}
}
複製代碼
##結語 本題在屬於分而治之思想的經典,分治法思想中的二分法類型,在leetcode上屬於困難題型,主要考察分治法思路設計以及算法複雜度的優化。最後,若是以爲本文對你有所幫助或啓發那就來個贊吧0.0~~