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)
中位数为 median = (MAX(C1) + MIN(C2)) /2 (m+n 为偶数) 或 MAX(C1) (m+n为奇数). (将median放在C1)
则任务转换为, 已知 A,B , 求满足上述条件的 MAX(C1),MIN(C2)
要满足条件1: 很容易满足....
要满足条件2: 由MAX(C1) <= MIN(C2) 可知
- MAX(C1中 来自A的元素) <= MIN(C2中 来自A的元素) (显然成立)
- MAX(C1中 来自A的元素) <= MIN(C2中 来自B的元素)
- MAX(C1中 来自B的元素) <= MIN(C2中 来自B的元素) (显然成立)
- MAX(C1中 来自B的元素) <= MIN(C2中 来自A的元素)
要满足条件3: C1.length == C2.length (或 C1.length == 1+ C2.length , 将median放在C2) , 设C1中 来自A的个数为x, 来自B的个数为y, 要满足
- C1.length = x + y , C2.length = m + n - x - y (或 m + n - x - y + 1)
即满足 y = (m + n + 1) /2 - x (利用除2向下取整,合并两种情况)
what?这个式子的意思就是 C1中 A的个数和B的个数满足线性关系, 这意味着啥?
这意味着 只要找到 x (C1中 A元素的数量) , 使得A,B 满足 条件2即可. 此话怎讲?
一个(x,y)的划分如图:
即满足:
- A[x-1] <= B[y]
- B[y-1] <= A[x]
临界值有 x =0, x = n , y = 0 , y = m(稍后讨论)
- 将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;
}
}
}
};

被折叠的 条评论
为什么被折叠?



