你須要的LeeCode題No.04——「尋找兩個有序數組的中位數」_一點課堂(多岸學院)

尋找兩個有序數組的中位數

題目:尋找兩個有序數組的中位數java

描述:給定兩個大小爲 m 和 n 的有序數組 nums1 和 nums2。請你找出這兩個有序數組的中位數,而且要求算法的時間複雜度爲 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

解析

看到題目以後,第一感受這不就是歸併排序嗎?因此能夠很快寫出如下代碼:code

public double findMedianSortedArrays(int[] nums1, int[] nums2) {
    if(nums1 == null || nums1.length == 0){
        return findMedianSortedArrays(nums2);
    }
    if(nums2 == null || nums2.length == 0){
        return findMedianSortedArrays(nums1);
    }

    int[] nums = new int[nums1.length+nums2.length];
    int index1 = 0;
    int index2 = 0;
    int index = 0;
    while (index1<nums1.length && index2<nums2.length) {
        if(nums1[index1]<nums2[index2]){
            nums[index++] = nums1[index1++];
        }else{
            nums[index++] = nums2[index2++];
        }
    }

    while(index1<nums1.length){
        nums[index++] = nums1[index1++];
    }

    while(index2<nums2.length){
        nums[index++] = nums2[index2++];
    }

    return findMedianSortedArrays(nums);
}

private double findMedianSortedArrays(int[] nums){
    int len = nums.length;
    if(len%2==1){
        return nums[len/2];
    }else{
        return (nums[len/2-1]+nums[len/2])/2.0;
    }
}

然而,歸併排序的這個過程須要O(max(m, n))的時間複雜度,這和題目的要求不符。要想達到O(log(m + n))級別的時間複雜度,必須使用一種和折半查找相似的方式。使用歸併排序的方式會把兩個數組合併成一個有序數組,再尋找它的中間值,有沒有可能不排序就找到這個值呢?blog

咱們假設兩個數組的中間值位置爲k,其中 k=(m+n)/2,只要找到這個值,也就找到了中位數,因此咱們能夠把問題轉換成查找兩個數組中第 k 大的數。排序

爲了更快的獲取到結果,咱們對較短的數組使用二分法,利用第 k 大的數前面必定有 k-1 個數這個屬性,肯定較長的數組應該劃分的位置,以下所示:圖片

file

由於第 k 大的值必定比第 a 大的值大,也必定比第 b 大的值大,因此咱們能夠將 a 和 b 中較小者以前的值所有拋棄,從而將求 m+n 個數中第 k 大的值,轉換成求 m+n-a(或 m+n-b)個數中第 k-a(或 k-b) 大的值。例如 a 處的值比 b 處的值小,咱們便將 a 以前的值所有拋棄,再進行下一次比較,以下所示:資源

file

尋找第 k 大的值的過程代碼以下:字符串

/**
 * 獲取第 k 大的值
 * 
 * @param nums1
 * @param nums2
 * @param len1 數組 1 使用的長度
 * @param len2 數組 2 使用的長度
 * @param start1 數組 1 有效的起點
 * @param start2 數組 2 有效的起點
 * @return 第 k 大的值
 */
private static int findMedianSortedArraysOptimize(int[] nums1, int[] nums2, int len1, int len2, int start1, int start2, int k){
    if(len1 > len2){
        return findMedianSortedArraysOptimize(nums2, nums1, len2, len1, start2, start1, k);
    }
    if(len1 == 0){
        return nums2[start2 + k - 1];
    }

    if(k == 1){
        return Math.min(nums1[start1], nums2[start2]);
    }

    int ignore1 = Math.min(k/2, len1);
    int ignore2 = k - ignore1;
    if(nums1[start1 + ignore1 - 1] < nums2[start2 + ignore2 - 1]){
        // 拋棄數組 1 比較位以前的值
        return findMedianSortedArraysOptimize(nums1, nums2, len1-ignore1, len2, start1+ignore1, start2, k-ignore1);
    }else if(nums1[start1 + ignore1 - 1] > nums2[start2 + ignore2 - 1]){
        // 拋棄數組 2 比較位以前的值
        return findMedianSortedArraysOptimize(nums1, nums2, len1, len2-ignore2,  start1, start2+ignore2, k-ignore2);
    }else{
        // 尋找到了第 k 大的值
        return nums1[start1+ignore1-1];
    }
}

找到了第 k 大的值,再尋找中位數就很簡單了,調用的代碼以下:

public double findMedianSortedArraysOptimize(int[] nums1, int[] nums2) {
    int len1 = nums1.length;
    int len2 = nums2.length;
    int k = (len1+len2)/2;
    if((len1+len2)%2 == 1){
        return findMedianSortedArraysOptimize(nums1, nums2, len1, len2, 0, 0, k+1);
    }else{
        return (findMedianSortedArraysOptimize(nums1, nums2, len1, len2, 0, 0, k) + findMedianSortedArraysOptimize(nums1, nums2, len1, len2, 0, 0, k+1))/2.0;
    }
}

總結

此題目告訴咱們同一個問題能夠有許多個解決方案,有時將問題轉換成其餘問題更有利於解決它。

下題預告

題目:最長迴文子串

描述:給定一個字符串 s,找到 s 中最長的迴文子串。你能夠假設 s 的最大長度爲 1000。

示例:

  • 輸入: "babad"
  • 輸出: "bab"
  • 注意: "aba" 也是一個有效答案。

相關源碼請在code目錄查看。


【感謝您能看完,若是可以幫到您,麻煩點個贊~】

更多經驗技術歡迎前來共同窗習交流: 一點課堂-爲夢想而奮鬥的在線學習平臺 http://www.yidiankt.com/

![關注公衆號,回覆「1」免費領取-【java核心知識點】] file

QQ討論羣:616683098

QQ:3184402434

想要深刻學習的同窗們能夠加我QQ一塊兒學習討論~還有全套資源分享,經驗探討,等你哦! 在這裏插入圖片描述

相關文章
相關標籤/搜索