求兩個排序陣列中位數,這道題是很有意思的一道題目,演算法導論中9.3-8題,這題必須在o(logn)的時間複雜度求解,否則肯定悲劇。。。
這題有個關鍵的條件,那就是這兩個陣列長度相等
思路如下:
陣列a:1, 3, 5, 7, 9
陣列b:2, 4, 6, 8, 10
首先取二者的中位數,在o(1)時間複雜度內求出,那麼陣列a的midvalue = 5,陣列b的midvalue = 6,則較小的元素midvalue的左邊所有元素,也就是midposition個,和較大元素右邊的所有元素,都要去掉,由於去掉的元素佔所有元素的一半,所以複雜度為o(logn)。只需要移動begin和end的position即可。
第一輪:
陣列a:1, 3,5, 7, 9
陣列b:2, 4, 6, 8, 10
第二輪:
陣列a:1, 3,5, 7, 9
陣列b:2,4, 6, 8, 10
只剩下兩個元素,由於這種情形下midvalue始終是偏左的元素,因此迴圈無法退出,所以滿足lhsbegin == lhsend - 1和 rhsbegin == rhsend - 1時,迴圈退出!
如果兩個
上述情形是當陣列中有兩個及以上元素才成立,必須考慮兩個陣列只存在乙個元素的情形,那麼直接取較小的元素即可!
[cpp]view plain
copy
#include
using
namespace
std;
intfindmidvalue(
int*lhs,
int*rhs,
intsize)
else
if(lhs[lhsmid] < rhs[rhsmid])
else
} if(lhsbegin == lhsend && rhsbegin == rhsend)
result = min(lhs[lhsbegin], rhs[rhsbegin]);
else
if(lhsbegin == lhsend - 1 && rhsbegin == rhsend - 1)
else
} return
result;
} void
main()
; int
rhs = ;
const
intsize =
sizeof
lhs /
sizeof
*lhs;
intresult = findmidvalue(lhs, rhs, size);
cout << "mid value = "
<< result << endl;
}
當兩個陣列長度不等時,這種情形比較複雜:
情形一:
當乙個陣列長度為1,另乙個陣列長度為奇數的情形:
例如a:1 b:2, 3, 4
這個時候的比較策略是,a的元素同b的中位數進行比較,若a的元素較小,則中位數一定是max(a[0], b[mid - 1]),若a的元素較大,則中位數一定是b[mid]
情形二:
例如a: 1 b:2, 3, 4, 5
這個時候的比較策略是,a的元素同b的中位數進行比較,若a的元素較小,則中位數一定是b[mid],若a的元素較大,則中位數一定是min(a[0], b[mid + 1])
下面引申一種情形:
當乙個陣列長度為2,另乙個陣列長度為奇數時:
例如a:1, 3 b:2, 4, 6
如果a[mid] < b[mid],那麼a[mid]肯定不會是中位數,由於a只有兩個元素,那麼a[1]將會是中位數的候選物件,那麼此情形退化為上面第一種情形
下面對乙個例子進行分析:
陣列a:1, 3, 5, 7, 9, 11
陣列b:2, 4, 6, 8
第一輪:
陣列a:1, 3, 5, 7, 9, 11
陣列b:2,4, 6, 8
第二輪:
陣列a:1,3, 5, 7
, 9,11
陣列b:2,4, 6, 8
進行到這裡,那麼刪除將不能再進行下去,可以肯定的是其中乙個陣列只有可能是1個或者2個元素,適用於上面分析的情形。
說下上面的刪除策略:
[cpp]view plain
copy
if(a[amid] < b[bmid])
即刪除較小的左邊元素和較大的右邊元素較小的個數。
刪除策略進行不下去還有一種情況,那就是rightb為0,當rightb為0時,b的元素只有可能是乙個,因為b有多個元素時,b的中位數右邊肯定還存在元素。
不難寫出**如下:
[cpp]view plain
copy
#include
using
namespace
std;
intfindmidvalue(
int*lhs,
intsizelhs,
int*rhs,
intsizerhs)
else
} else
if(lhsleft == 0)
else
} //lhs two elems
else
else
} else
} } else
else
} break
; }
lhsbegin = lhsbegin + minvalue;
rhsend = rhsend - minvalue;
}
else
else
} else
if(rhsleft == 0)
else
} //rhs two elems
else
else
} else
} } else
else
} break
; }
lhsend = lhsend - minvalue;
rhsbegin = rhsbegin + minvalue;
} }
return
result;
} void
main()
; int
rhs = ;
const
intsize1 =
sizeof
lhs /
sizeof
*lhs;
const
intsize2 =
sizeof
rhs /
sizeof
*rhs;
intresult = findmidvalue(lhs, size1, rhs, size2);
cout << "mid value = "
<< result << endl;
}
(rhsend - rhsbegin) & 0x01成立表示有偶數個陣列,不信用筆畫一畫下標index~~~
關於中位數的其他求法,羅列如下:
1,題目
有兩個陣列,均已經按公升序排列好,程式設計序計算這兩個陣列的中位數
要求:要求時間複雜度o(lgn) 空間複雜度o(1)
例子:
陣列a: b 兩陣列合併後 中位數就是中間的那個數: 5
2,方法:
對兩個陣列分別二分找解
對每個元素可以o(1)判斷它在另外乙個陣列應該所在的位置,從而可以判斷選大了還是小了,繼續二分直到找到解為止
先二分第乙個陣列找解,可選區域為[0,4]。選中a[2]=6,6前面有兩個元素,如果將其插入第二個陣列,那麼6如果是解,則必須前面有4-2=2個元素(排第三位)
通過比較前後元素發現6放在b中的第三位明顯大了,需要更小的元素,這樣就將下一次二分的區域減了一半.
在a和b中重複這個過程,直到找到解為止
3,3,擴充套件
m個長度為n的排序好的陣列 求中位數
目前有兩個比較好的演算法
演算法一
(1)取所有陣列的最小值和最大值,求出全體的最大值和最小值min max 然後取m=(min+max)/2
(2)用m在所有陣列中搜尋 找到比m小的數的個數n1 若n1大於m*n/2 則mid=(min+mid)/2 否則mid=(mid+max)/2
(3)重複上述搜尋一共迴圈log(max-min)次
演算法二
(1)取所有陣列的中值排序
棄掉這個最大值所在陣列的後半部分和最小值所在陣列的前半部分 再將這兩個只剩一半的陣列合併 o(n)
(2)從合併後的陣列中找出中值插入到之前的中值排序陣列裡 o(logn)
(3)重複(1)(2),每次迴圈可以捨掉乙個陣列,一共需要迴圈m次
思想與本文實質相同!
分享到:
兩個排序陣列的中位數
求兩個排序陣列中位數,這道題是很有意思的一道題目,演算法導論中9.3 8題,這題必須在o logn 的時間複雜度求解,否則肯定悲劇。這題有個關鍵的條件,那就是這兩個陣列長度相等 思路如下 陣列a 1,3,5,7,9 陣列b 2,4,6,8,10 首先取二者的中位數,在o 1 時間複雜度內求出,那麼陣...
兩個排序陣列的中位數
兩個排序的陣列a和b分別含有m和n個數,找到兩個排序陣列的中位數,要求時間複雜度應為o log m n 給出陣列a 1,2,3,4,5,6 b 2,3,4,5 中位數3.5 給出陣列a 1,2,3 b 4,5 中位數 3 public double findmediansortedarrays in...
兩個排序陣列的中位數
來自leetcode的兩個排序陣列的中位數 給定兩個大小為 m 和 n 的有序陣列 nums1 和 nums2 請找出這兩個有序陣列的中位數。要求演算法的時間複雜度為 o log m n 你可以假設 nums1 和 nums2 不同時為空。思路 合併陣列 對陣列排序 得到中位數 片.findmedi...