您的位置:首页 > 其它

求两个排序数组的中间值

2015-11-08 22:20 363 查看
题目:数组A、B分别已经按照升序进行排列,元素个数分别为N1和N2。求这两个数组的中间值。

定义:当两个数组的元素个数之和为奇数时,中间数为两个数组归并排序后,排在中间的那个数;当两个数组的元素个数之和为偶数时,中间数为两个数组归并排序后,中间的两个数的平均值。

解决的思路:

将两个数组分别拆成两半,使得两个数组左半边的元素个数之和等于右半边的元素个数之和。

下面给出3种解法:

解法1:

import sys
class Solution(object):
def findMedianSortedArrays(self, nums1, nums2):
N1 = len(nums1)
N2 = len(nums2)
if N1 < N2:
return self.findMedianSortedArrays(nums2, nums1)
if N1 == 0:
return 0
elif N2 == 0:
return (nums1[(N1-1)/2] + nums1[N1/2]) / 2.0
flag = (N1 + N2) % 2 == 0
Half = (N1 + N2) / 2 if flag else (N1 + N2) / 2 + 1
lo = 0
hi = N1 - 1
while lo <= hi:
mid = (hi + lo) / 2
C1 = mid + 1
C2 = Half - C1
if C2 > N2:
lo = mid + 1
continue
elif C2 == 0:
if nums1[C1 - 1] > nums2[C2]:
hi = mid - 1
continue
R1 = sys.maxint if C1 >= N1 else nums1[C1]
return nums1[C1 - 1] if not flag else (nums1[C1 - 1] + min(R1, nums2[0])) / 2.0
elif C2 < 0:
hi = mid - 1
continue

if C2 < N2 and nums1[C1 - 1] > nums2[C2]:
hi = mid - 1
elif C2 > 0 and nums2[C2 - 1] > nums1[C1]:
lo = mid + 1
else:
R1 = sys.maxint if C1 == N1 else nums1[C1]
L1 = -sys.maxint - 1 if C1 == 0 else nums1[C1 - 1]
R2 = sys.maxint if C2 == N2 else nums2[C2]
L2 = -sys.maxint - 1 if C2 == 0 else nums2[C2 - 1]
return max(L1, L2) if not flag \
else (max(L1, L2) + min(R1, R2)) / 2.0
if hi < 0:
L1 = -sys.maxint - 1
R1 = nums1[0]
L2 = nums2[Half - 1]
R2 = sys.maxint if Half == N2 else nums2[Half]
return (max(L1, L2) + min(R1, R2)) / 2.0

解法2:
class Solution(object):
def findMedianSortedArrays(self, nums1, nums2):
N1 = len(nums1)
N2 = len(nums2)
if N1 > N2:
N1, N2, nums1, nums2 = N2, N1, nums2, nums1
if N2 == 0:
return 0
elif N1 == 0:
return (nums2[(N2-1)/2] + nums2[N2/2]) / 2.0
flag = (N1 + N2) % 2 == 0
Half = (N1 + N2 + 1) / 2
lo = 0
hi = N1
while lo <= hi:
C1 = (hi + lo) / 2
C2 = Half - C1
if C1 > 0 and C2 < N2 and nums1[C1 - 1] > nums2[C2]:
hi = C1 - 1
elif C2 > 0 and C1 < N1 and nums2[C2 - 1] > nums1[C1]:
lo = C1 + 1
else:
if C2 == 0:
L = nums1[C1 - 1]
elif C1 == 0:
L = nums2[C2 - 1]
else:
L = max(nums1[C1 - 1], nums2[C2 - 1])
if not flag:
return L
if C1 == N1:
R = nums2[C2]
elif C2 == N2:
R = nums1[C1]
else:
R = min(nums1[C1], nums2[C2])
return (L+R) / 2.0


解法3:
import sys
class Solution(object):
def findMedianSortedArrays(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: float
"""
N1 = len(nums1)
N2 = len(nums2)
if N1 < N2:
return self.findMedianSortedArrays(nums2, nums1)
if N1 == 0:
return 0
elif N2 == 0:
return (nums1[(N1-1)/2] + nums1[N1/2]) / 2

lo = 0
hi = 2 * N1
while lo <= hi:
mid = (lo + hi) / 2
C1 = mid
C2 = N1 + N2 - C1
L1 = nums1[(C1 - 1) / 2] if C1 != 0 else -sys.maxint - 1
R1 = nums1[C1 / 2] if C1 != 2 * N1 else sys.maxint
L2 = nums2[(C2 - 1) / 2] if C2 != 0 else -sys.maxint - 1
R2 = nums2[C2 / 2] if C2 != 2 * N2 else sys.maxint

if L1 > R2:
hi = mid - 1
elif L2 > R1:
lo = mid + 1
else:
return (max(L1, L2) + min(R1, R2)) / 2.0
return -1
其中解法1代码最繁琐,解法3最简洁。解法1和解法2的结题思路相同,都是遍历数组A左半边元素的个数,根据数组A左半边元素个数确定数组B左半边的元素个数。最终可以找到一种分割方式,使得数组A、B左半边的元素的数值比右半边的元素的数值都小,此时,可以根据分割的边界确定中间值。
解法1之所以比解法2繁琐,主要是由于没有选择好数组A。假设某一次分割中,数组A左边元素个数为C1,则数组B左边的元素个数为C2=(N1+N2+1)/2-C1。如果B[C2-1]>A[C1],需要增加C1后继续迭代。此时,如果N1<N2,可以保证下一次迭代,mid=(lo + hi)/2的数值不会超过(N1+N2+1)/2,从而保证C2>0。而如果N1>N2,则无法保证下一次迭代C2>0,因此需要额外添加许多判断逻辑。

解法3的思路较难想到,是从leetcode上copy过来的。具体证明过程见原文https://leetcode.com/discuss/41621/very-concise-iterative-solution-with-detailed-explanation。原文在推导index_L和index_R与N的关系时,只证明了分割点为数组中间值的情况。一般情况可以从该特殊情况出发,分N为奇数和偶数两种情况进一步推导得到。最终可以发现一般情况与特殊情况的切割点左右的下标表达式与特殊情况相同。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  排序 数组 中间值