LeetCode 4——兩個排序數組中的中位數

1. 題目

2. 解答

2.1. 方法一

因爲兩個數組都是排好序的,所以首先能夠想到的思路就是利用歸併排序把兩個數組合併成一個有序的長數組,而後直接取出中位數便可。python

class Solution:
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        
        len1 = len(nums1)
        len2 = len(nums2)
        nums = []
        
        i = 0
        j = 0
        
        while (i < len1 and j < len2):
            
            if (nums1[i] <= nums2[j]):
                nums.append(nums1[i])
                i += 1
            
            else:
                nums.append(nums2[j])
                j += 1
        
        if (i < len1):
            while(i < len1):
                nums.append(nums1[i])
                i += 1
            
        if (j < len2):
            while(j < len2):
                nums.append(nums2[j])
                j += 1
        
        odd = (len1 + len2) % 2 # 長度是否爲奇數
        mid = (len1 + len2 - 1) // 2
        if (odd):
            return nums[mid]
        else:
            return (nums[mid] + nums[mid+1]) / 2

由於要遍歷兩個數組,因此時間複雜度爲 $O(m+n)$,而題目中要求算法的時間複雜度爲 $O(log (m+n))$,所以應該是有更高效的算法,藉助於二分查找。算法

2.2. 方法二
所謂中位數,就是將 K 個數據分爲長度相等的兩組,左邊的數據小於等於右邊的數據。

若是咱們要在任意位置 $i$ 處將長度爲 $m$ 的數組 $A$ 分爲兩部分,則共有 $m+1$ 種分法,$i=[0, m]$。數組

$$ left\_part \quad | \quad right\_part$$
$$ A[0], A[1], ..., A[i-1] \quad | \quad A[i], A[i+1], ..., A[m-1]$$app

$i=0$ 說明左半部分沒有元素,反之 $i=m$ 說明右半部分沒有元素。左半邊元素個數爲 $i$ ,右半邊元素個數爲$m-i$。spa

同理,咱們能夠在任意位置 $j$ 處將長度爲 $n$ 的數組 $B$ 分爲兩部分,則共有 $n+1$ 種分法,$j=[0, n]$。code

$$ B[0], B[1], ..., B[j-1] \quad | \quad B[j], B[j+1], ..., B[n-1]$$排序

針對劃分完後的數組 $A$ 和 $B$,若是知足:rem

  • 左邊部分的長度等於右邊部分的長度(偶數狀況),$i+j = m-i + n-j$;或者等於右邊部分的長度加 1(奇數狀況) ,$i+j = m-i + n-j+1$。
  • 左邊的最大元素小於等於右邊的最小元素,$A[i-1] <= B[j] \quad and \quad B[i-1] <= A[j]$。

那咱們也就找到了中位數,$median = \frac{max(left\_part) + min(right\_part)}{2}$。it

因此,咱們要作的就是在 $i=[0, m]$ 區間搜索一個 $i$ 值,使得上面的條件獲得知足。也即io

$$ A[i-1] <= B[j] \quad and \quad B[i-1] <= A[j] ,其中 \quad j = \frac{m+n+[1]}{2}-i$$

加不加 1 取決於總的長度是奇數仍是偶數,同時,爲了保證 $j$ 的範圍在 $[0, n]$,咱們必需要求 $n <= m$

接下來,咱們就在 $i=[0, m]$ 區間進行二分查找。

    1. 若是知足條件,則直接返回求取中位數。
    1. 若是 $i > 0 \quad and \quad A[i-1] > B[j]$,則減少 $i$。若是增長 $i$,則 $j$ 減少,左邊序列數組 $A$ 的值會更大,右邊序列數組 $B$ 的值會更小。
    1. 若是 $i < m \quad and \quad B[i-1] > A[j]$,則增長 $i$。若是減少 $i$,則 $j$ 增長,左邊序列數組 $A$ 的值會更小,右邊序列數組 $B$ 的值會更大。

最後,咱們求得左半部分的最大值以及右半部分的最小值,而後就能夠求出中位數了。

由於,要查找的範圍爲 $i=[0, m]$,並且每次查找縮小區間爲原來的一半,所以時間複雜度爲 $O(log(min(m, n))$,空間複雜度爲 $O(1)$。

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        
        
        int m = nums1.size();
        int n = nums2.size();
        int len = m + n;
        int odd = len % 2;
        
        int left = 0;
        int i = 0, j = 0;  
        vector<int>::iterator A = nums1.begin();
        vector<int>::iterator B = nums2.begin();
        
        // 確保數組 A 的長度小於等於數組 B 的長度
        if (m > n)
        {
            int temp = m;
            m = n;
            n = temp;
            A = nums2.begin();
            B = nums1.begin();
        }
        
        int right = m;
                
        while(left <= right)
        {
            i = left + (right - left) / 2;
            j = (len + odd) / 2 - i;
                        
            if (i > 0 && A[i-1] > B[j])
            {
                right = i - 1;
            }
            else if(i < m && B[j-1] > A[i])
            {
                left = i + 1;
            }
            else
            {
                break;
            } 
        }
         
        int left_max = 0;
        int right_min = 0;
        
        // 左半部分的最大值
        if (i == 0) left_max = B[j-1];
        else if (j == 0) left_max = A[i-1];
        else  left_max = A[i-1] <= B[j-1] ? B[j-1] : A[i-1];

        // 右半部分的最小值
        if (i == m) right_min = B[j];
        else if (j == n) right_min = A[i];
        else    right_min = A[i] <= B[j] ? A[i] : B[j];

        if (odd)
        {
            return left_max;
        }
        else
        {
            return float(left_max + right_min) / 2;
        }
    }
};

獲取更多精彩,請關注「seniusen」!

相關文章
相關標籤/搜索