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


第4題


給定兩個大小為 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

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/median-of-two-sorted-arrays

中位數定義

將一個集合划分為兩個長度相等的子集,其中一個子集中的元素總是大於另一個子集中的元素。

解題思路

將數組進行切。

  • 長度為 m 的數組,有 0 到 m 總共 m + 1 個位置可以切。

  • 把數組 A 和數組 B 分別在 i 和 j 進行切割。

  • 將 i 的左邊和 j 的左邊組合成「左半部分」,將 i 的右邊和 j 的右邊組合成「右半部分」。

當 A 數組和 B 數組的總長度是偶數時,如果我們能夠保證

  • 左半部分的長度等於右半部分 \(i+j=m-i+n-j\), 也就是 \(j=(m+n)/2-i\)

  • 左半部分最大的值小於等於右半部分最小的值 \(max(A[i-1],B[j-1])<=min(A[i],B[j])\)

那么,中位數就可以表示如下

\((左半部分最大值+右半部分最小值)/2\)==>\((max(A[i-1],B[j-1])+min(A[i],B[j]))/2\)

當 A 數組和 B 數組的總長度是奇數時,如果我們能夠保證

  • 左半部分的長度比右半部分大1,即\(i+j=m-i+n-j+1\) 也就是 \(j=(m+n+1)/2-i\)

  • 左半部分最大的值小於等於右半部分最小的值 \(max(A[i-1],B[j-1]) <=min(A[i],B[j])\)

那么,中位數就是

左半部分最大值,也就是左半部比右半部分多出的那一個數==>\(max(A[i-1],B[j-1])\)

對以上條件進行分析

第一個條件

我們其實可以合並為 \(j=(m+n+1)/2-i\),因為如果\(m+n\) 是偶數,由於我們取的是 int 值,所以加 1 也不會影響結果。當然,由於 \(0<=i<=m\),為了保證 \(0<=j<=n\),我們必須保證 \(m<=n\)

  • \(m≤n,i<m,j=(m+n+1)/2−i≥(m+m+1)/2−i>(m+m+1)/2−m=0\)

  • \(m≤n,i>0,j=(m+n+1)/2−i≤(n+n+1)/2−i<(n+n+1)/2=n\)

最后一步由於是 int 間的運算,所以 \(1/2=0\)

第二個條件

奇數和偶數的情況是一樣的,我們進一步分析。

為了保證 \(max(A[i-1],B[j-1])<=min(A[i],B[j])\),因為 A 數組和 B 數組是有序的,所以 $A[i-1]<=A[i],B[i-1]<=B[i] 這是一定的,所以我們只需要保證 \(B[j-1]<=A[i]和A[i-1]<=B[j]\),即我們要分兩種情況討論:

  • \(B[j-1]>A[i]\),並且為了不越界,要保證 \(j!= 0,i!=m\),此時很明顯,我們需要增加 i ,為了數量的平衡還要減少 j ,幸運的是 \(j=(m+n+1)/2-i\),i 增大,j 自然會減少。

  • \(A[i-1]>B[j]\),並且為了不越界,要保證 \(i!=0,j!=n\),此時和上邊的情況相反,我們要減少 i ,增大 j 。

上邊兩種情況,我們把邊界都排除了,需要單獨討論。

  • 當 i=0, 或者 j=0,也就是切在了最前邊。此時左半部分當 j = 0 時,最大的值就是 \(A[i-1]\) ;當 i=0 時 最大的值就是 \(B[j-1]\)。右半部分最小值和之前一樣。

  • 當 i = m 或者 j = n,也就是切在了最后邊。此時左半部分最大值和之前一樣。右半部分當 \(j=n\) 時,最小值就是 \(A[i]\);當 i = m 時,最小值就是\(B[j]\)

所有的思路都理清了,最后一個問題,增加 i 的方式。當然用二分了。初始化 i 為中間的值,然后減半找中間的,減半找中間的,減半找中間的直到答案。

源代碼

class Solution {
    public double findMedianSortedArrays(int[] A, int[] B) {
        int m = A.length;
        int n = B.length;
        if (m > n) { 
            return findMedianSortedArrays(B,A); // 保證 m <= n
        }
        int iMin = 0, iMax = m;
        while (iMin <= iMax) {
            int i = (iMin + iMax) / 2;
            int j = (m + n + 1) / 2 - i;
            if (j != 0 && i != m && B[j-1] > A[i]){ // i 需要增大
                iMin = i + 1; 
            }
            else if (i != 0 && j != n && A[i-1] > B[j]) { // i 需要減小
                iMax = i - 1; 
            }
            else { // 達到要求,並且將邊界條件列出來單獨考慮
                int maxLeft = 0;
                if (i == 0) { maxLeft = B[j-1]; }
                else if (j == 0) { maxLeft = A[i-1]; }
                else { maxLeft = Math.max(A[i-1], B[j-1]); }
                if ( (m + n) % 2 == 1 ) { return maxLeft; } // 奇數的話不需要考慮右半部分

                int minRight = 0;
                if (i == m) { minRight = B[j]; }
                else if (j == n) { minRight = A[i]; }
                else { minRight = Math.min(B[j], A[i]); }

                return (maxLeft + minRight) / 2.0; //如果是偶數的話返回結果
            }
        }
        return 0.0;
    }
}

總結

  • 時間復雜度

我們對較短的數組進行了二分查找,所以時間復雜度是 \(O(log(min(m,n)))\)

  • 空間復雜度

只有一些固定的變量,和數組長度無關,所以空間復雜度是 \(O(1)\)

資料


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM