要求: 给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。 例如: nums1 = [1, 3] nums2 = [2] 则中位数是 2.0 nums1 = [1, 2] nums2 = [3, 4] 则中位数是 (2 + 3)/2 = 2.5
算法解析:
中位数:将一个集合划分为两个长度相等的子集,其中一个子集中的元素总是大于另一个子集中的元素。 1. 两个有序的数组分别为:A和B。其中A长度为m,B长度为n 我们把A分成两部分: left(A) | right(A) A[0],A[1]...A[i-1] | A[i],A[i+2]...A[m-1] 其中len(left(A)) + len(right(A)) = m 把B分成两部分: left(B) | right(B) B[0],B[1]...B[j-1] | B[j],B[j+2]...B[n-1] 其中len(left(B)) + len(right(B)) = n 2. 所以我们把两个数组结合到一起 left_part | right_part left(A)+left(B) | right(A)+right(B) 其中:len(left_part) = i + j; len(right_part) = m-i+n-j 要找到AB两个数组的中位数,则需满足: len(left_part) == len(right_part);如果m+n总长度为奇数则这里把多出的哪一个元素放在左边,所以len(left_part) == len(right_part)+1 max(left_part) <= min(right_part);由于数组A和数组B都是有序数组,则需满足A[i-1] <= B[j], B[j-1] <= A[i] 转换成公式如下: i+j = m-i+n-j+1 i+j = (m+n+1)/2 j = (m+n+1)/2 - i; 此时当i=m临界值时,j = (n-m+1)/2, 所以n >= m 3. 先通过二分法方式定位数组A中的一个元素,再通过上面的公式也就能确定数组B中的元素了 设imin := 0; imax := m,在[imin,imax]中进行搜索 i = imin+imax / 2; 则 j = m+n+1+imin+imax / 2才能满足len(left_part) == len(right_part) 此时我们已经满足了len(left_part) == len(right_part) 下面需要满足A[i-1] <= B[j]&& B[j-1] <= A[i] 但是我们会遇到不满足的情况 比如: 如果A[i-1] > B[j],则i需要减少,i和j是成反相关的,所以j就会增加,通过二分法,则i会向左边分,i= i+imin / 2 如果B[j-1] > A[i],则j需要减少,i则需要增加,i会向右边分, i = i + imax / 2
代码实现:
// findMedianSortedArrays查找两个数组的中位数
func findMedianSortedArrays(A []float64, B []float64) float64 {
// 通过上面的分析得,len(B) >= len(A)
if len(A) > len(B) {
temp := A
A = B
B = temp
}
m := len(A)
n := len(B)
// 通过上面的分析,通过二分法先锚定A中的i
imin := 0
imax := m
for imin <= imax {
i := (imin + imax) / 2
j := (m+n+1)/2 - i
//
if A[i-1] > B[j] && i > imin{
// i需要减少,则下一个i在二分法的左边
imax = i
} else if B[j-1] > A[i] && i < imax{
// i需要增加,则下一个i在二分法中的右边
imin = i
} else {
// 表示满足条件A[i-1] <= B[j]&& B[j-1] <= A[i]
// 计算中位数,找到左边的最大值和右边的最小值
leftMax := 0.0
if i == 0 {
// 表示左边只有B
leftMax = B[j-1]
} else if j == 0 {
// 表示左边只有A
leftMax = A[i-1]
} else {
leftMax = math.Max(A[i-1],B[j-1])
}
if (m+n)%2 == 1 {
return leftMax
}
// 找到右边的最小值
rightMin := 0.0
if i == m {
// 表示右边只有B
rightMin = B[j]
} else if j == n {
// 表示右边只有A
rightMin = A[i]
} else {
rightMin = math.Min(A[i],B[j])
}
return (leftMax + rightMin) / 2
}
}
// 表示没有找到
return 0.0
}