两个不同长度的排序数组的中位数
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)) 的解决方案。以上是关于两个不同长度的排序数组的中位数的主要内容,如果未能解决你的问题,请参考以下文章