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

分析:关键在于理解中位数的实际含义,即将一群数分割成数目相同的两部分,并且右边的数始终不小于(大于或等于)左边的数,也就是右边的最小值大于等于左边的最大值。明白了这个,在去解这题,对于整数数组 A[0~m] 和 整数数组 B[0~n],在0~m中寻找分割位 i,在 0~n 中寻找分割位 j

First let's cut A into two parts at a random position i:

      left_A             |        right_A
A[0], A[1], ..., A[i-1] | A[i], A[i+1], ..., A[m-1]

Since A has m elements, so there are m+1 kinds of cutting( i = 0 ~ m ). And we know: len(left_A) = i, len(right_A) = m - i . Note: when i = 0 , left_A is empty, and when i = m , right_A is empty.

With the same way, cut B into two parts at a random position j:

      left_B             |        right_B
B[0], B[1], ..., B[j-1] | B[j], B[j+1], ..., B[n-1]

Put left_A and left_B into one set, and put right_A and right_B into another set. Let's name them left_part and right_part :

      left_part          |        right_part
A[0], A[1], ..., A[i-1] | A[i], A[i+1], ..., A[m-1]
B[0], B[1], ..., B[j-1] | B[j], B[j+1], ..., B[n-1]

(上面要注意的是可能构成左,右部分的只有A或B,即A和B被全部扔到了左边部分或右边部分)

If we can ensure:

1) len(left_part) == len(right_part)
2) max(left_part) <= min(right_part)

then we divide all elements in {A, B} into two parts with equal length, and one part is always greater than the other. Then median = (max(left_part) + min(right_part))/2.

To ensure these two conditions, we just need to ensure:

(1) i + j == m - i + n - j (or: m - i + n - j + 1)
if n >= m, we just need to set: i = 0 ~ m, j = (m + n + 1)/2 - i
(2) B[j-1] <= A[i] and A[i-1] <= B[j]

上面之所以加1是考虑到了 m+n 是奇数的情形,如果m+n是偶数(m=3, n=3),比如是6,那么加1除2和不加1除2结果是一样的都是3,这是如果i=2,那么j=1,left_part是(A[0],A[1],B[0]),right_part是(A[2],B[1],B[2])。如果m+n是奇数(m=3,n=4),7+1除2结果是4,如果i=2,那么j=2,left_part是(A[0],A[1],B[0],B[1]),right_part是(A[2],B[2],B[3])。这时左右部分个数并不相等,因为对于总数为奇数的情形来说本来就不能将其分为个数相等的两个部分,不过从上面的分析可以得知,在总数是偶数时可以保证两部分个数相等,此时的中位数等于左边部分的最大值加上右边部分的最小值再除以2,当总数是奇数时可以保证中位数分到了左边部分,即此时的中位数等于左边部分的最大值。

So, all we need to do is:

Searching i in [0, m], to find an object `i` that:
B[j-1] <= A[i] and A[i-1] <= B[j], ( where j = (m + n + 1)/2 - i )

上面要确保m<n,否则索引会出现负数,如果开始输入的两个数组其长度m>n,代码上交换一下数组即可。

And we can do a binary search following steps described below:

<1> Set imin = 0, imax = m, then start searching in [imin, imax]

<2> Set i = (imin + imax)/2, j = (m + n + 1)/2 - i

<3> Now we have len(left_part)==len(right_part). And there are only 3 situations
that we may encounter:
<a> B[j-1] <= A[i] and A[i-1] <= B[j]
Means we have found the object `i`, so stop searching.
<b> B[j-1] > A[i]
Means A[i] is too small. We must `ajust` i to get `B[j-1] <= A[i]`.
Can we `increase` i?
Yes. Because when i is increased, j will be decreased.
So B[j-1] is decreased and A[i] is increased, and `B[j-1] <= A[i]` may
be satisfied.
Can we `decrease` i?
`No!` Because when i is decreased, j will be increased.
So B[j-1] is increased and A[i] is decreased, and B[j-1] <= A[i] will
be never satisfied.
So we must `increase` i. That is, we must ajust the searching range to
[i+1, imax]. So, set imin = i+1, and goto <2>.
<c> A[i-1] > B[j]
Means A[i-1] is too big. And we must `decrease` i to get `A[i-1]<=B[j]`.
That is, we must ajust the searching range to [imin, i-1].
So, set imax = i-1, and goto <2>.

When the object i is found, the median is:

max(A[i-1], B[j-1]) (when m + n is odd)
or (max(A[i-1], B[j-1]) + min(A[i], B[j]))/2 (when m + n is even)

Now let's consider the edges values i=0,i=m,j=0,j=n where A[i-1],B[j-1],A[i],B[j] may not exist. Actually this situation is easier than you think.

What we need to do is ensuring that max(left_part) <= min(right_part). So, if i and j are not edges values(means A[i-1],B[j-1],A[i],B[j] all exist), then we must check both B[j-1] <= A[i] and A[i-1] <= B[j]. But if some of A[i-1],B[j-1],A[i],B[j] don't exist, then we don't need to check one(or both) of these two conditions. For example, if i=0, then A[i-1] doesn't exist, then we don't need to check A[i-1] <= B[j]. So, what we need to do is:

Searching i in [0, m], to find an object `i` that:
(j == 0 or i == m or B[j-1] <= A[i]) and
(i == 0 or j == n or A[i-1] <= B[j])
where j = (m + n + 1)/2 - i

And in a searching loop, we will encounter only three situations:

<a> (j == 0 or i == m or B[j-1] <= A[i]) and
(i == 0 or j = n or A[i-1] <= B[j])
Means i is perfect, we can stop searching. <b> j > 0 and i < m and B[j - 1] > A[i]
Means i is too small, we must increase it. <c> i > 0 and j < n and A[i - 1] > B[j]
Means i is too big, we must decrease it.

As: i < m ==> j > 0 and i > 0 ==> j < n . Because:

m <= n, i < m ==> j = (m+n+1)/2 - i > (m+n+1)/2 - m >= (2*m+1)/2 - m >= 0
m <= n, i > 0 ==> j = (m+n+1)/2 - i < (m+n+1)/2 <= (2*n+1)/2 <= n

So in situation <b> and <c>, we don't need to check whether j > 0 and whether j < n.

上面是在考虑边界的情形,在搜索 i 的过程中,因为 j = (m + n + 1)/2 - i,所以我们只需要关注中位数的第二个条件即可,即右边部分的最小值不小于左边部分的最大值,对于分割位i和j,因为数组A和B自身已经是排过序的了,所以首先想到的是比较A[i-1]和B[j],以及B[j-1]和A[i].但是如果i=0,i=m以及j=0,j=m 时该如何判断,以i=0为例,这中情况表明A数组所有数被分到了右边的部分,这种情况大概发生在B数组的个数远大于A数组的情形,此时的中位数在完全的B数组中寻找,j = (m + n + 1)/2 - i,那么j取到的位置就是中间位置,如果此时B[j-1]<=A[i],保证了左边的最大小于或等于右边所有的数,那j的位置就是中位数的位置(或j-1和j)。分析了这么多,其实结论就一个,也就是说当i=0时,只需要满足情形a中与判断的第一条件即可。

代码:

class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m=nums1.length;
int n=nums2.length;
int[] A=nums1;
int[] B=nums2;
if(m>n){
int temp1=m;
m=n;
n=temp1;
int[] temp2=A;
A=B;
B=temp2;
} int max_left=0;
int min_right=0;
// i+j=m-i+n-j+1
int imin=0,imax=m,half_len=(m+n+1)/2;//出于奇偶的考虑
while(imin<=imax){
int i=(imin+imax)/2;
int j=half_len-i;
if(i<m && B[j-1]>A[i]) imin=i+1;
else if(i>0 && A[i-1]>B[j]) imax=i-1;
else{
       // i is perfect,先求max_left再求max_right
if(i==0){        // A被全部放到了右边
max_left=B[j-1];
}else if(j==0){    // B被全部放到了右边
max_left=A[i-1];
}else{         // 一般情形
max_left=Math.max(A[i-1],B[j-1]);
} if((m+n)%2==1) return max_left; if(i==m){
min_right=B[j];
}else if(j==n){
min_right=A[i];
}else{
min_right=Math.min(A[i],B[j]);
}
return (max_left+min_right)/2.0;
}
}
return -1;
}
}

LeetCode解题报告—— Median of Two Sorted Arrays的更多相关文章

  1. 《LeetBook》leetcode题解(4): Median of Two Sorted Arrays[H]——两个有序数组中值问题

    我现在在做一个叫<leetbook>的免费开源书项目,力求提供最易懂的中文思路,目前把解题思路都同步更新到gitbook上了,需要的同学可以去看看 书的地址:https://hk029.g ...

  2. 【LeetCode】4. Median of Two Sorted Arrays (2 solutions)

    Median of Two Sorted Arrays There are two sorted arrays A and B of size m and n respectively. Find t ...

  3. leetcode.C.4. Median of Two Sorted Arrays

    4. Median of Two Sorted Arrays 这应该是最简单最慢的方法了,因为本身为有序,所以比较后排序再得到中位数. double findMedianSortedArrays(in ...

  4. 【一天一道LeetCode】#4 Median of Two Sorted Arrays

    一天一道LeetCode (一)题目 There are two sorted arrays nums1 and nums2 of size m and n respectively. Find th ...

  5. 【LeetCode OJ】Median of Two Sorted Arrays

    题目链接:https://leetcode.com/problems/median-of-two-sorted-arrays/ 题目:There are two sorted arrays nums1 ...

  6. 【LeetCode】4. Median of Two Sorted Arrays 寻找两个正序数组的中位数

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 公众号:负雪明烛 本文关键词:数组,中位数,题解,leetcode, 力扣,python ...

  7. 【leetcode】4. Median of Two Sorted Arrays

    题目描述: There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of t ...

  8. leetcode第二题--Median of Two Sorted Arrays

    Problem:There are two sorted arrays A and B of size m and n respectively. Find the median of the two ...

  9. Leetcode Array 4 Median of Two Sorted Arrays

    做leetcode题目的第二天,我是按照分类来做的,做的第一类是Array类,碰见的第二道题目,也就是今天做的这个,题目难度为hard.题目不难理解,但是要求到了时间复杂度,就需要好好考虑使用一下算法 ...

随机推荐

  1. HDU 2083(排序+绝对值+中间值求和)

    简易版之最短距离 点我跳转到HDOJ Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...

  2. bzoj Usaco补完计划(优先级 Gold>Silver>资格赛)

    听说KPM初二暑假就补完了啊%%% 先刷Gold再刷Silver(因为目测没那么多时间刷Silver,方便以后TJ2333(雾 按AC数降序刷 ---------------------------- ...

  3. 「LibreOJ NOIP Round #1」七曜圣贤

    题目啰嗦:支持三个操作: 不可重复集合:1.加入一个数 2.删除一个数 3.恢复目前最早的一次删除的数 操作可能不合法,每次有效操作之后求集合的mex(最小没有出现过的数) 50组数据+1e6,必须O ...

  4. [NOIP 2017]棋盘

    题目描述 有一个 m×m 的棋盘,棋盘上每一个格子可能是红色.黄色或没有任何颜色的.你现在要从棋盘的最左上角走到棋盘的最右下角. 任何一个时刻,你所站在的位置必须是有颜色的(不能是无色的), 你只能向 ...

  5. iOS-查询数据库-->指定数据表中的当前数据行的总数量

    很多时候,我们在查询一个表的时候,不想得到里面的记录内容,只是想简单的得到符合查询条件的记录条数. FMDB中有一个很简单的方法就可以实现,见下面的代码实例: #import "FMdata ...

  6. HDU4009:Transfer water(有向图的最小生成树)

    Transfer water Time Limit: 5000/3000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)To ...

  7. Sql Server 2008 R2 数据库脚本导出方法

    经常忘记怎么搞,截几张图记录一下. 1 选中要导出的数据库,右键—>任务—>生成脚本 2 3 4 查看保存的脚本

  8. [mysql]tpcc相关及画图

    参考:http://blog.chinaunix.net/uid-26896862-id-3563600.html 参考:http://blog.chinaunix.net/uid-25266990- ...

  9. ACM1198Farm Irrigation

    这个题目好吓人呀!嘿嘿--- 不过仔细分析下就可以啦! #include<iostream> #include<cstring> using namespace std; ; ...

  10. 【20161109】noip模拟赛

    1.Game [题目描述] 明明和亮亮在玩一个游戏.桌面上一行有n个格子,一些格子中放着棋子.明明和亮亮轮流选择如下方式中的一种移动棋子(图示中o表示棋子,*表示空着的格子): 1) 当一枚棋子的右边 ...