4. Median of Two Sorted Arrays
There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
Example 1:
nums1 = [1, 3] nums2 = [2] The median is 2.0
Example 2:
nums1 = [1, 2] nums2 = [3, 4] The median is (2 + 3)/2 = 2.5
題意理解:
給定任意兩個已經排好序的數組, 要你求這兩個數組的中位數. 並且時間複雜度不能大於O(log (m+n) )
思路歷程:
1. 合併成一個數組, 再求其中位數. 於是想到了合併的算法(按思考的時間先後)
- 插入排序. 粗略一算, 時間複雜度爲O(m*n).
- 二分插入. 粗略一算, 複雜度爲 O(nlogm), (假設n<m)
可以看出要達到log(m+n)這個等級, 合併這條路走不通.
2. 逆推法. 假設成功合併了nums1(簡稱A,長度爲n) 和nums2(簡稱B,長度爲m), 得到一個數組C .通過觀察C和它的中位數median可初步得到以下結論
- C.length = m + n
- 對於任意的 c1 ∈ C1, c2 ∈ C2 均有 c1 <= c2, 即 MAX(C1) <= MIN(C2)
- median可把M分成左半部分(C1), 和右半部分(C2). 並且C1.length == C2.length (或 C1.length == C2.length + 1, 將median放在C1)
- MAX(C1中 來自A的元素) <= MIN(C2中 來自A的元素) (顯然成立)
- MAX(C1中 來自A的元素) <= MIN(C2中 來自B的元素)
- MAX(C1中 來自B的元素) <= MIN(C2中 來自B的元素) (顯然成立)
- MAX(C1中 來自B的元素) <= MIN(C2中 來自A的元素)
- C1.length = x + y , C2.length = m + n - x - y (或 m + n - x - y + 1)
- A[x-1] <= B[y]
- B[y-1] <= A[x]
- 將x 從 0 到 n 進行順序遍歷, 這樣複雜度爲O(n)
- 從0到n 對x 進行二分查找, 這樣複雜度爲O(logn)
var left = 0;
var right = A.length;
while(left <= right)
{
var x = (left + right) / 2;
var y = (A.length + B.length + 1) / 2 - x;
if(A[x-1] > B[y])
{
//說明A[x-1]太大了.
//如果 x增大, 則y會減少, 這樣A[x-1]會更加比B[y]大.
//所以 x應該減少.
right = x;
}
else if(B[y-1] > A[x])
{
//說明A[x]太小了
//如果 x減小,則 y會增大, 這樣B[y-1]會比A[x]更大.
//所以 x應該增大.
left = x;
}
else {
//說明x剛好滿足條件2.
var MAXA = A[x-1];
var MINB = B[y];
if((A.length + B.length )%2 == 0)
{
return (MAXA + MINB) / 2;
}
else{
return MAXA*1.0;
}
}
}
下面討論 x=0 , x=n, y=0, y=m的情況- C1中 A爲空集 (導致A[x-1] 不存在)
- C2中 A爲空集 (導致A[x]不存在)
- C1中 B爲空集 (導致B[y-1]不存在)
- C2中 B爲空集 (導致B[y]不存在)
<span style="white-space:pre"></span>if (x !== 0 && y !== B.length && A[x - 1] > B[y]) {
//說明A[x-1]太大了.
//如果 x增大, 則y會減少, 這樣A[x-1]會更加比B[y]大.
//所以 x應該減少.
right = x - 1;
}
else if (y !== 0 && x !== A.length && B[y - 1] > A[x]) {
//說明A[x]太小了
//如果 x減小,則 y會增大, 這樣B[y-1]會比A[x]更大.
//所以 x應該增大.
left = x + 1;
}
在獲取最後結果的時候要也要判斷://說明x剛好滿足條件2.
if (x === 0) {
var MAX_C1 = B[y - 1];
}
else if (y === 0) {
var MAX_C1 = A[x - 1];
}
else {
var MAX_C1 = A[x - 1] > B[y - 1] ? A[x - 1] : B[y - 1];
}
if (x === A.length) {
var MIN_C2 = B[y];
}
else if (y === B.length) {
var MIN_C2 = A[x];
}
else {
var MIN_C2 = A[x] > B[y] ? B[y] : A[x];
}
if ((A.length + B.length) % 2 == 0) {
return (MAX_C1 + MIN_C2) / 2;
}
else {
return MAX_C1 * 1.0;
}
以下爲完整代碼:
/**
* @param {number[]} A
* @param {number[]} B
* @return {number}
*/
var findMedianSortedArrays = function (A, B) {
//確保 A.length < B.length 實現 log(MIN(m,n))
if (A.length > B.length) {
var temp = B;
B = A;
A = temp;
}
var left = 0;
var right = A.length;
while (left <= right) {
var x = parseInt((left + right) / 2);
var y = parseInt((A.length + B.length + 1) / 2) - x;
if (x !== 0 && y !== B.length && A[x - 1] > B[y]) {
//說明A[x-1]太大了.
//如果 x增大, 則y會減少, 這樣A[x-1]會更加比B[y]大.
//所以 x應該減少.
right = x - 1;
}
else if (y !== 0 && x !== A.length && B[y - 1] > A[x]) {
//說明A[x]太小了
//如果 x減小,則 y會增大, 這樣B[y-1]會比A[x]更大.
//所以 x應該增大.
left = x + 1;
}
else {
//說明x剛好滿足條件2.
if (x === 0) {
var MAX_C1 = B[y - 1];
}
else if (y === 0) {
var MAX_C1 = A[x - 1];
}
else {
var MAX_C1 = A[x - 1] > B[y - 1] ? A[x - 1] : B[y - 1];
}
if (x === A.length) {
var MIN_C2 = B[y];
}
else if (y === B.length) {
var MIN_C2 = A[x];
}
else {
var MIN_C2 = A[x] > B[y] ? B[y] : A[x];
}
if ((A.length + B.length) % 2 == 0) {
return (MAX_C1 + MIN_C2) / 2;
}
else {
return MAX_C1 * 1.0;
}
}
}
};