資料結構演算法題 兩個有序陣列的中位數

2021-08-29 07:18:40 字數 2820 閱讀 7629

有三種方法,時間複雜度分別是o(m+n) ,o(k),o(log(m+n))

注意點:

判斷合併後的陣列的元素個數是奇數還是偶數

如果是奇數取中間值;如果是偶數取中間2個數的平均值。

兩種求中位數的方法:

方法1,判斷奇數個還是偶數個

if (lengthall % 2 == 0)else

方法2,不需要判斷奇數個還是偶數個

int l = (lengthall+1)/2-1;

int r = (lengthall+2)/2-1;

//上面減1的原因是座標從0開始的

result = (all[l] + all[r])*1.0/2;

//這種求中位數的方法不需要判斷是奇數還是偶數個

思考:

中位數相當於合併之後的top(n/2),如果是其他top數也是可以的。所以如果是乙個無序陣列的top k就只用小頂堆。如果是兩個有序陣列合併之後的top k就可以用如下的方法。

(1)o(m+n)合併兩有序數組成乙個新有序陣列,再按中間位置取值。

兩個有序陣列合併為乙個有序陣列的時間複雜度o(m+n)。請參考

/**1

* o(m+n)

* 合併兩有序數組成乙個新有序陣列,再按中間位置取值

* @param nums1

* @param nums2

* @return

*/public static double findmediansortedarrays1(int nums1, int nums2)

if (inx1 + inx2 == (lengthall + 2) / 2)

if (inx1 == length1)}}

if (inx2 < length2)

if (inx1 + inx2 == (lengthall + 2)/2)

if (inx2 == length2)}}

}return -1;

}

(3)o(log(m+n))兩個陣列分別採用二分法查詢

思想:上面的是陣列num1,下面是陣列num2。

使用遞迴的思想分別對num1和num2求中位數,因為是有序的,所以直接取n/2處的值即可。

有個前提:合併後陣列的中位數一定大於等於單個陣列的中位數。

(1)如果num1的中位數=num2的中位數,那麼就是最終的結果。

(2)如果num1的中位數(3)如果num1的中位數》num2的中位數,那麼下次就在[a,c]和[e,f]兩個新陣列直接找中位數。

(4)重複這個步驟,直到新陣列的長度為2

方法:二分+遞迴

--看到有序,並且明確要求時間複雜度為log級的,肯定需要二分。但是請注意,很多人一看到二分,就想也不想的開始對陣列進行二分,但是對於這題,對陣列二分就進了死胡同了。這題是對另乙個量進行二分。

--再分析中位數的特徵,就是求陣列中的某乙個(或兩個)數,其左右兩邊的個數相等

--設兩個有序陣列分別為,a,長度m;b,長度n

--那麼這個中位數,就是,a和b合併後的第(m+n+1)/2個(先不管有2個中位數的情況,後面會有個小技巧來遮蔽奇偶差異)

--那麼現在的問題就變成了,求兩個有序陣列中,從小到大的第k個值

--所以二分其實是對k進行二分,兩個陣列同時從0開始,每次往後跳k/2個,當然不是同時跳,誰更小才能跳,保證已經跳過的數在整個陣列中是最小的

private int findkth(int array1, int start1, int end1, int array2, int start2, int end2, int k)

if(start2>end2)

if(k==1)

int mid1=integer.max_value;

int mid2=integer.max_value;

//這裡的思想,其實不是每次移動整個end-start的一半,而是移動k的一半

if(start1+k/2-1<=end1)

if(start2+k/2-1<=end2)

if(mid1如果陣列a的中位數小於陣列b的中位數,那麼整體的中位數只可能出現在a的右區間加上b的左區間之中; 

如果陣列a的中位數大於等於陣列b的中位數,那麼整體的中位數只可能出現在a的左區間加上b的右區間之中。 

關鍵就是利用分治的思想逐漸縮小a的區間和b的區間來找到中位數。

首先假設陣列a和b的元素個數都大於k/2,我們比較a[k/2-1]和b[k/2-1]兩個元素,這兩個元素分別表示a的第k/2小的元素和b的第k/2小的元素。這兩個元素比較共有三種情況:>、《和=。如果a[k/2-1]

當a[k/2-1]>b[k/2-1]時存在類似的結論。

當a[k/2-1]=b[k/2-1]時,我們已經找到了第k小的數,也即這個相等的元素,我們將其記為m。由於在a和b中分別有k/2-1個元素小於m,所以m即是第k小的數。(這裡可能有人會有疑問,如果k為奇數,則m不是中位數。這裡是進行了理想化考慮,在實際**中略有不同,是先求k/2,然後利用k-k/2獲得另乙個數。)

通過上面的分析,我們即可以採用遞迴的方式實現尋找第k小的數。此外我們還需要考慮幾個邊界條件:

如果a或者b為空,則直接返回b[k-1]或者a[k-1];

如果k為1,我們只需要返回a[0]和b[0]中的較小值;

如果a[k/2-1]=b[k/2-1],返回其中乙個;

資料結構 陣列 (六) 合併兩個有序陣列

leetcode 88 給定兩個有序整數陣列 nums1 和 nums2,將 nums2 合併到 nums1 中,使得 num1 成為乙個有序陣列。說明 示例 輸入 nums1 1,2,3,0,0,0 m 3 nums2 2,5,6 n 3 輸出 1,2,2,3,5,6 題解 public stat...

Leetcode演算法題 兩個有序陣列求中位數

思路 暴力解決 合併陣列並排序,簡單且一定能實現,時間複雜度o m n 由於兩個陣列已經排好序,可一邊排序一邊合併,用時為第一種的一半,時間複雜度依然為o m n 由題目,只需要找中位數,即中位數兩側的元素並不需要完全排序,且兩陣列長度已知且有序,合併後中位數的索引是固定的,所以只要找到這乙個或計算...

演算法題 兩個有序陣列求中位數

leetcode上遇到的一道題,感覺很有意思 因為要求o log m n 所以第一反應時用二分來找,但是該怎麼用二分呢?陣列a,b分別有序,我們可以先找到陣列a中的一條分界線i,使得陣列a分為a left,和a right兩部分,那麼因為時要找到中位數,我們可以直接計算出b陣列的一條分界線j,使得s...