/*** * 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] * * The median is 2.0 * Example 2: * * nums1 = [1, 2] * nums2 = [3, 4] * * The median is (2 + 3)/2 = 2.5 * */
/*** * 關鍵: * 本題的難點是要有了複雜度,也就是log(n+m) 看見log咱們所能想到的確定是用到了分冶法,這裏是二分查找 */
public class N004_MedianOfTwoSortedArrays { /*** * * 咱們經過切一刀,可以把有序數組分紅左右兩個部分,切的那一刀就被稱爲割(Cut),割的左右會有兩個元素,分別是左邊最大值和右邊最小值。 * * 咱們定義L = Max(LeftPart),R = Min(RightPart) * * 雙數組 * 咱們設: * Ci爲第i個數組的割。 * Li爲第i個數組割後的左元素. * Ri爲第i個數組割後的右元素。 * * 如何從雙數組裏取出第k個元素 * 首先Li<=Ri是確定的(由於數組有序,左邊確定小於右邊) * 若是咱們讓L1<=R2 && L2<=R1 * * 那麼左半邊 全小於右半邊,若是左邊的元素個數相加恰好等於k,那麼第k個元素就是Max(L1,L2),參考上面常識1。 * 若是 L1>R2,說明數組1的左邊元素太大(多),咱們把C1減少,把C2增大。L2>R1同理,把C1增大,C2減少。 * * 下面具體來看特殊狀況的中值問題。 * * 雙數組的奇偶 * 中值的關鍵在於,如何處理奇偶性,單數組的狀況,咱們已經討論過了,那雙數組的奇偶問題怎麼辦,m+n爲奇偶處理方案都不一樣, * * 讓數組恆爲奇數 * 有沒有辦法讓兩個數組長度相加必定爲奇數或偶數呢? * * 其實有的,虛擬加入‘#’(這個trick在manacher算法中也有應用),讓數組長度恆爲奇數(2n+1恆爲奇數)。 * *分治的思路 * 有了上面的知識後,如今的問題就是如何利用分治的思想。 * * 怎麼分? * 最快的分的方案是二分,有2個數組,咱們對哪一個作二分呢? * 根據以前的分析,咱們知道了,只要C1或C2肯定,另一個也就肯定了。這裏,爲了效率,咱們確定是選長度較短的作二分,假設爲C1。 * * 怎麼治? * 也比較簡單,咱們以前分析了:就是比較L1,L2和R1,R2。 * - L1>R2,把C1減少,C2增大。—> C1向左二分 * - L2>R1,把C1增大,C2減少。—> C1向右二分 * * 越界問題 * 若是C1或C2已經到頭了怎麼辦? * 這種狀況出如今:若是有個數組徹底小於或大於中值。可能有4種狀況: * - C1 = 0 —— 數組1總體都比中值大,L1 >R2,中值在2中 * - C2 = 0 —— 數組1總體都比中值小,L1 * */ public static double findMedianSortedArrays(int[] nums1, int[] nums2) { int INT_MIN = -1, INT_MAX = 999999; int n = nums1.length; int m = nums2.length; if (n > m) { //保證數組1必定最短 return findMedianSortedArrays(nums2, nums1); } int L1 = 0, L2 = 0, R1 = 0, R2 = 0, c1 = 0, c2 = 0, lo = 0, hi = 2 * n; //咱們目前是虛擬加了'#'因此數組1是2*n長度 while (lo <= hi) //二分 { c1 = (lo + hi) / 2; //c1是二分的結果 c2 = m + n - c1; L1 = (c1 == 0) ? INT_MIN : nums1[(c1 - 1) / 2]; //map to original element R1 = (c1 == 2 * n) ? INT_MAX : nums1[c1 / 2]; L2 = (c2 == 0) ? INT_MIN : nums2[(c2 - 1) / 2]; R2 = (c2 == 2 * m) ? INT_MAX : nums2[c2 / 2]; if (L1 > R2) hi = c1 - 1; else if (L2 > R1) lo = c1 + 1; else break; } return (Math.max(L1, L2) + Math.min(R1, R2)) / 2.0; } public static void main(String args[]) { int[] nums1 = {1, 2}; int[] nums2 = {3, 4}; double result = findMedianSortedArrays(nums1, nums2); System.out.println(result); } }