【翻自LeetCode】求两排序后数组的中位数

来源:互联网 发布:降温软件排行第一 编辑:程序博客网 时间:2024/04/29 21:56

翻译来自1337c0d3r在LeetCode的文章。我在做Median of Two Sorted Arrays这道题目时遇到了困难,在评论区找到的这篇文章,边翻边看。

原文在这:点击打开链接

解:

         如果你在goolge上搜索这个问题,你会发现成吨的结果。他们中的大部分都是m==n时的特殊情况,尽管如此,他们的代码还是充满了bug。《算法导论》中将这道题目作为9.3-8章节的练习题,但还是在m==n的前提下求解。我在网上找到的唯一一个适用于更普遍条件的靠谱解法是将中位数定义为位于中间位置的单个元素(他们用二叉树搜索的解法十分整齐)。但是根据维基百科上中位数的定义,当m+n是偶数时,中位数应该是这两个数的平均值。

         如果你读过我之前的帖子:在两个排序好的数列中寻找合并后第k个最小数,那你会发现这两个问题在某些地方有点相似。事实上,当(m + n)为奇数时,寻找中位数可以想成这个问题在k = (m+n)/2时的特例。尽管当(m + n)为偶数时我们仍然可以通过两次使用这个方法来找到两个位于中间值,但是这样会效率低下。

         你可能会问:为什么不用之前的方法来解决这个问题?毕竟之前的方法解决的是一个更普遍的例子。当然,我尝试过这样做,但我认为之前的解法不适用与这个问题。主要原因是当(m + n)为偶数时,两个中间的元素有可能在同一个数组里。这样整个算法就会复杂化并且出现许多特例,不得不一个一个地来处理他们。

         与寻找第k个最小数相似,比较自然的方法是将他们切分成子问题后解决。首先我们选择Aj和Bj(A和B的中间数),i和j分别为m/2和n/2。我们观察下,如果Ai<=Bj,那么中位数一定在Ai和Bj中间的某个地方(包含Ai和Bj)。既然如此,我们可以去掉从Ai左边共计i个元素,从Bj右边开始共计n-j-1个元素。请特别注意不要把Ai或者Bj去掉,因为我们可能需要两个中间元素来计算中位数(可能出现两个中间元素在同个数列里的情况)。当Ai > Bj时情况类似。

两个排序后的数组A和B。i为m/2,j为n/2。Ai和Bj是A和B的中间元素。如果Ai< Bj,中位数一定在Ai和Bj中间(包含端点)。相反的情况类似。

 

像上面说的方法在大部分情况下是正确的,但是这样有一点,那就是从各个数组删除的元素个数可能是不同的。看上面的例子:如果Ai <= Bj,Ai左边的两个元素和Bj右边的三个元素被删除。这样就不再是一个合法的子问题了,因为两个子数组的中位数都不再是所求的中位数。

因此我们必须确保:

从各个数组放置进来的元素数目必须相同。

这可以通过从各个数组里选择删除元素的数目来很容易地达成(警告:下面的例子在一个边缘特例失效,更多细节请看EDIT部分):

k = min(i, n-j-1) when Ai<= Bj.                   <---1(a)

k = min(m-i-1, j) when Ai> Bj.                    <---1(b)

了解怎样继续分隔这个问题是比较容易的(递归)。难的是找出递归终止条件(何时结束切割)。

很显然当m=1或者n=1时,你必须将它当做特例来对待,否则会陷入死循环。难点在于推导出为什么m=2或者n=2时需要特例处理。(提示:两个中间数可能位于同一个数组。)

最终,贯彻上面的方法转化为一个十分棘手的编程练习。在看下面的解法之前,尝试挑战下自己。

如果有更优雅的解法来处理这个问题,我十分乐意看到他们。

EDIT(修正):

感谢第一个指出这个bug的人Algorist。(更多细节请阅读评论)。这个bug在一些边际特例出现,并且在测试数据里没有发现。

稍后我将修正这个bug,我自己又另外发现了一个我之前的代码会出现的bug。

一个例子是这样的:

A = { 1, 2, 4, 8, 9, 10 }
B = { 3, 5, 6, 7 }

前面的条件在这个例子上出现了错误,应该返回5.5却返回了5。

这个问题出现的原因是数字5本来应该在最后计算的时候考虑在内,但在第一次迭代的时候就被舍弃了。为了解决这个边际问题,我们应该在数组长度为偶数时更加小心地去除相邻元素。下面是解决这个问题的正确条件2(a), 2(b)2(c)2(d) )

k = min(i-1, n-j-1) when Ai <= Bj and m is even.   <--- 2(a)
k = min(i, n-j-1)   when Ai <= Bj and m is odd.    <--- 2(b)
k = min(m-i-1, j-1) when Ai > Bj  and n is even.   <--- 2(c)
k = min(m-i-1, j)   when Ai > Bj  and n is odd.    <--- 2(d)


0 0
原创粉丝点击