两个不同长度的排序数组的中位数

Posted

技术标签:

【中文标题】两个不同长度的排序数组的中位数【英文标题】:Median of two sorted arrays of different length 【发布时间】:2018-06-28 02:51:18 【问题描述】:

我试图理解在 O(log(n+m)) 中解决此问题的算法,其中 n 和 m 是数组的长度。我冒昧地发布了该算法解释的链接:

https://www.geeksforgeeks.org/median-of-two-sorted-arrays-of-different-sizes/

我很难完全消化这个算法背后的想法。我可以看到这个想法是将其中一个数组的长度减少到 1 或 2,然后应用基本情况。基本情况是有道理的,但我想知道是否可以省略 n = 2 的基本情况而只处理 n = 1。我也不了解其余情况部分。对我来说,这看起来很奇怪,我们必须将数组 B[] 从开头切到 idx。这很奇怪,因为 idx 可以等于 B[] 的长度,所以我们会忽略整个数组。

【问题讨论】:

你不明白二分搜索的工作原理吗? -------------是的,二分搜索是通过将数据集减半来寻找事物的艺术。 所以看我们有 array a = "aaaaaaaaaa" array b = "bbbbbbbbbbbbbbbbbbbb" 如果我​​们合并它们并排序它会像这样 "abababbabababbbbababaaba",我们的目标是在每一步中采取最数组的中间部分,所以 "ababab[bababbabbbbab]abaaba" 我们想要 a1 和 a2、a1 和 b1、a1 和 b2、a2 和 b1、a2 和 b2,还是 b1 和 b2。所以我们有 6 种取一半元素的可能性,我们通过比较中间元素来决定,其中肯定是我们所有的中间元素 但是其中一些案例没有意义,所以我们可以跳过它们 【参考方案1】:

TL;DR:

主要思想是,您可以从数字集中删除肯定小于(或等于)中位数的 N 个元素,只要删除肯定大于或等于的相同数量。

我们用一个例子来解释一下:

A=[1 2 3 9 10],B=[3 4 5 6 7 8 9]

中间标记的元素:

A=[1 2 3 9 10],B=[3 4 5 6 7 8 9]

总体中位数将介于 3 和 6 之间(含)。因此,如果我们删除两个小于 3 的元素和两个大于 6 的元素,我们仍然会有相同的中位数。我们从 A 中删除较小的元素,从 B 中删除较大的元素:

A=[3 9 10],B=[3 4 5 6 7]

现在我们删除一个大于 9 的元素(从 A 中)和一个小于 5 的元素(从 B 中):

A=[3 9],B=[4 5 6 7]

我们达到了案例 4(较小的数组有 2 个元素):算法要求中位数为

B[M/2], B[M/2 – 1], max(A[0], B[M/2 – 2]), min(A[1], B[M/2 + 1] ])

为 B[2], B[1], max(A[0], B[0]), min(A[1], B[3])

为 6, 5, max(3,4), min(9,7)

存在 [6 5 4 7]

该数组的中位数是 5.5。这就是正确的结果。

【讨论】:

我们可以一直减少数据集直到其中一个数组的大小为 1 吗? A = [3],B = [5 6 7] @Dan 你是对的,没有必要用二元素数组停止算法。 B中位数为5.5,A中位数为6,完全可以删除A中的9和B中的4。最后你可以删除A中的3和B中的7,使A为空,取中位数从 B 是 [5 6]。 @RalfKleberhoff 如果我们像你说的那样继续清空 A 并将 B 减少到 2,那么时间复杂度将为 O(log(max(m,n))) 而不是 O(log(min (m,n))) ??【参考方案2】:
def findmedian(A,B):
    if len(A) > len(B):
        return findmedian(B,A)# always ensuring that we do the binsearch on the shorter arr
    x = len(A)
    y = len(B)
    start = 0# start and end of shorter arr
    end = x
    while (start <= end):
        partition_x = (start + end)//2# the mid of smaller arr, partition_x is an index
        partition_y = (x+y+1)//2 - partition_x# the suitable partition of larger arr to divide the arrs into equal halves
        if partition_x == 0:# if there is nothing on the left
            left_x = None
        if partition_x == x:# if there is nothing on the right
            right_x = sys.maxint# +inf
        if partition_y == 0:
            left_y = None# this is -inf similar to the case for smaller arr
        if partition_y == y:
            right_y = sys.maxint

        if (left_x <= right_y) and (left_y <= right_x):# all the elems on left are smaller than all the elems on right is ensured by
         #checking on the extremes only since arrs sorted. Also, the partition always makes equal halves, so found the right spot.
            if (x+y) % 2 == 0:
                return (max(left_x,left_y) + min(right_x,right_y))/2.0
            else:
                return max(left_x,left_y)# if the num of elems is odd
            elif left_x > right_y:# if we have come more towards right of smaller arr, then move left on smaller arr
                end = partition_x -1
            else:# if we have come more to the left
                start = partition_x + 1

【讨论】:

【参考方案3】:
    class Solution(object):
      def findMedianSortedArrays(self, nums1, nums2):
      merged_array = (nums1 + nums2)
      merged_array.sort()
      l_m_a = len(merged_array)
      count = int(l_m_a / 2)

      if l_m_a % 2 == 1:
        median = merged_array[count]
        return median
      else:
        median_in_even = (merged_array[count] + merged_array[count - 1]) / 2
        return median_in_even

【讨论】:

【参考方案4】:

对我来说,这只是几行 python 代码的几分钟,它通过了 leetcode 检查,运行时击败了 62% 的 Python3 在线提交。我的代码在这里:


class Solution:
    def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
        n = len(nums1) + len(nums2)
        nums1.extend(nums2)  # merge two lists
        nums1.sort()  # sort it
        if n % 2 == 0:
            return (nums1[n//2-1] + nums1[n//2])/2 # return the median for even n
        else:
            return nums1[n//2] # return the median for odd n

【讨论】:

哦,现在我知道我错了。我的解决方案给出了 O(n log(n)) 的时间复杂度,但问题要求 O(log (n)) 的解决方案。

以上是关于两个不同长度的排序数组的中位数的主要内容,如果未能解决你的问题,请参考以下文章

递归打卡1在两个长度相等的排序数组中找到上中位数

递归训练1:在两个?长度相等的排序数组中找到上中位数

算法总结之 在两个长度相等的排序数组中找到上中位数

等长排序数组的中位数

有序数组寻找中位数以及寻找K大元素

求数组总和的中位数