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

思路一 歸併排序

此題是兩個有序數組中查找第K小的數的特例,而我能想到的查找第K個元素便是使用歸併排序算法(鄧公的<<數據結構>>講的非常不錯)。所以,一開始我是按照歸併排序的思路+第K個元素停止的來做的。但一開始我沒想到可以把整個查找函數提取出來進行封裝,當時寫的有點複雜。
在查看一些解題思路後,得到啓發,把查找函數提出來後,代碼易讀性與簡潔性得到了很大的提升。
關於時間複雜度,題目要求O(log(n+m)),但此思路的時間複雜度爲O(n+m),一般情況下的時間複雜度默認最壞時間複雜度。因此在時間複雜度的要求上,這個思路是不滿足的。但從提交的結果來看,算法實際消耗的時間還是可以令人滿足的。

代碼

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        int xSize=nums1.size();
        int ySize=nums2.size();
        int total = xSize+ySize;
        if((xSize+ySize)&0x01) return find_Kth(nums1,xSize,nums2,ySize,total/2+1);
        else return (find_Kth(nums1,xSize,nums2,ySize,total/2)+find_Kth(nums1,xSize,nums2,ySize,total/2+1))/2;
    }
private:
    double find_Kth(vector<int>& nums1,int xSize,vector<int>& nums2,int ySize,int target){
        int xIndex=0;
        int yIndex=0;
        int loken=0;
        double value;
        while(xIndex<xSize||yIndex<ySize){
            if((xIndex<xSize)&&(!(yIndex<ySize)||nums1[xIndex]<=nums2[yIndex])){
                value=nums1[xIndex];
                xIndex++;
                loken++;
                if(loken==target) return value;
            }
            if((yIndex<ySize)&&(!(xIndex<xSize)||(nums2[yIndex]<nums1[xIndex]))){
                value=nums2[yIndex];
                yIndex++;
                loken++;
                if(loken==target) return value;
            }
        }
        return 0;
    }
};

結果

在這裏插入圖片描述

思路二

設定ia,ib。其中ia、ib滿足一下條件:

  • m<k/2時,ia=m;否則ia=k/2
  • ib+ia=k,ib=k-ia
    ia指示的是A中前ia個元素,ib指示的是B中前ib個元素。

當A[ia]=B[ib]時,因爲ia+ib=k,所以第k個元素=A[ia]=B[ib],返回A[ia]或B[ib];
當A[ia]<B[ib]時,可以確定A中前ia個元素,一定是前k/2小的元素。B[ib]<A[ia]時,B中前ib個元素,一定是前k/2小的元素。所以可以遞歸調用查找函數,修改一定的條件。

這個算法的思路實現並不算難,但是難就難在了邊界條件的確定。目前對於這一塊,我並沒有很深入的理解,可能需要一定的題量支持。就對三個邊界發生的情況做下解釋:

  • 第一個是說,A的範圍必須比B的範圍小。因爲ia取值時,考慮了A的範圍,但是B取值時,並沒有考慮。
  • 第二個是說,A爲空,但A爲空有兩種可能,一種是輸入時就是空的,另一種是,在執行過程中,A的範圍不斷變小而發生的。
  • 第三個是說,k=1。這個也是有兩種,與上述情況類似。

代碼

class Solution {
public:
    double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
        const int m=nums1.size();
        const int n=nums2.size();
        int total=m+n;
        if(total&0x01)
            return find_Kth(nums1.begin(),m,nums2.begin(),n,total/2+1);
        else 
            return (find_Kth(nums1.begin(),m,nums2.begin(),n,total/2+1)+find_Kth(nums1.begin(),m,nums2.begin(),n,total/2))/2;
    }
private:
    double find_Kth(vector<int>::const_iterator A,int m,vector<int>::const_iterator B,int n,int k){
        if(m>n) return find_Kth(B,n,A,m,k);
        if(m==0) return *(B+k-1);
        if(k==1) return min(*A,*B);

        int ia=min(k/2,m);
        int ib=k-ia;
        if(*(A+ia-1)<*(B+ib-1)) return find_Kth(A+ia,m-ia,B,n,k-ia);
        else if(*(B+ib-1)<*(A+ia-1)) return find_Kth(A,m,B+ib,n-ib,k-ib);
        else return A[ia-1];
    }
};

結果

在這裏插入圖片描述

參考資源

Leetcode 題解
Leetcode

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章