![947cee830a3a3c9fa99a8100e12addb1.png](https://i-blog.csdnimg.cn/blog_migrate/16c27b1fd81e7de164454cf36dd3e96a.jpeg)
package main
import (
"fmt"
"math"
)
/*
给定两个大小为 m 和 n 的有序数组 A 和 B,请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 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
}
func main() {
A := []float64{1,3}
B := []float64{2,3,4,5}
middle := findMedianSortedArrays(A,B)
fmt.Println(middle)
}
![7d567389eff628d37907bdd979478267.png](https://i-blog.csdnimg.cn/blog_migrate/7ea2834d32ee36915866abce717dad89.png)