004_MedianOfTwoSortedArrays

/***
 * 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);
    }
}
本站公眾號
   歡迎關注本站公眾號,獲取更多信息