思路:
利用中位数的特性,左边的数的个数=右边的数个数。
假设合并后的数组(实际上不会真的合并),中位数的位置是k,那么我们查找两个正序的数组,找到一个位置为i,另外一个位置为j,使得nums1[i] <= nums2[j+1] && nums1[i+1] >= nums2[j],由题设可知,nums1[:i] + nums2[:j] <= nums1[i+1:] + nums2[j+1:],
令i+j = k ,那么中位数就是nums1[:i]+nums2[:j]里面的最后一个元素,因为是有序数组,所以mid_num=max(nums1[i],nums2[j])
所以我们查找中位数的过程就变成了求解二元一次方程k=i+j,其中k已知
程序设计:
1、二分法移动查找nums1的i,则nums2的j=k-i
2、当nums1[i] > nums2[j+1] && nums1[i+1] >= nums2[j]时,说明i需要减小,j需要增大
3、当nums1[i] <= nums2[j+1] && nums1[i+1] < nums2[j]时,说明i需要增大,j需要减小
4、当nums1[i] > nums2[j+1] && nums1[i+1] < nums2[j]时,因为数组有序,nums1[i+1]>=nums1[i] && nums2[j+1]>= nums2[j],这种情况属于数据异常,即入参非题设要求的正序数组
func is_odd_number(num int) bool {
b := num % 2
if b == 0 {
return false
} else {
return true
}
}
func findMedianSortedArrays() (median float32) {
nums1 := []int{1, 2, 3, 4, 5, 6, 7, 8, 9}
nums2 := []int{1,2,3,4,5,6}
var max_nums []int
var min_nums []int
// 使用最小的数组进行查找效率更高
if len(nums1) >= len(nums2) {
max_nums, min_nums = nums1, nums2
} else {
max_nums, min_nums = nums2, nums1
}
max_nums_length := len(max_nums)
min_nums_length := len(min_nums)
total_length := max_nums_length + min_nums_length
is_odd_event := is_odd_number(total_length)
k := total_length / 2 // 无论奇偶数都取前面一个数进行处理,其偶数情况的中位数结果特殊处理即可
if is_odd_event {
k += 1
}
// 最小元素数组为0时,取最大的数组的k位置的为中位数
if min_nums_length == 0 {
if is_odd_event {
median = float32(max_nums[k-1])
} else {
median = float32(max_nums[k-2] + max_nums[k-1])
}
return
}
var left, right, i int = 0, min_nums_length - 1, 0
// 注意k=i+j 是一个数学上的数值关系表达式,下面的i、j均是转换成了数组的下标,所以i取不到min_nums_length,即right=min_nums_length-1
for {
i = (left + right) / 2 // 二分且是下标值
j := k - i - 1 - 1 // i因为取下标本身就是再数值上面减1,而j=k-i表示的是数值,所以需-1得到j的数值,再减1则表示j下标
var L1, R1, L2, R2 int
L1 = min_nums[i]
// 当没有i+1的元素时,取i表示
if i+1 >= min_nums_length {
R1 = min_nums[i]
} else {
R1 = min_nums[i+1]
}
L2 = max_nums[j]
// 当没有j+1的元素时,取j表示
if j+1 >= max_nums_length {
R2 = max_nums[j]
} else {
R2 = max_nums[j+1]
}
if L1 <= R2 && R1 >= L2 {
if L1 >= L2 {
// 合并后的数组为奇数,取k元素即可
if is_odd_event {
L2 = L1
} else {
// 避免越界,取不到,L2自然就是排到k-1的位置
if i-1 >= 0 {
// 取第k-1元素
if L2 < min_nums[i-1] {
L2 = min_nums[i-1]
}
}
}
} else {
if is_odd_event {
L1 = L2
} else {
if j-1 >= 0 {
if L1 < max_nums[j-1] {
L1 = max_nums[j-1]
}
}
}
}
return float32(L1+L2) / 2
} else if L1 <= R2 && R1 < L2 {
//i需要增大,j需要减小
left = i + 1
// 无法找到满足条件的i+j的关系,说明min_nums的全部小于中位数,中位数是max_nums数组的k-min_nums_length位
if left >= right {
if is_odd_event {
// L1 = L2
median = float32( max_nums[k-min_nums_length-1])
} else {
// L1 = R2
median = float32(max_nums[k-min_nums_length-1] + max_nums[k-min_nums_length]) / 2
}
// mid = float32(L1+L2) / 2
return
}
} else if L1 > R2 && R1 >= L2 {
// i需要减小,j需要增大
right = i - 1
// 无法找到满足条件的i+j的关系,说明min_nums的全部大于中位数,中位数在max_nums的前k项
if left > right {
if is_odd_event {
median = float32( max_nums[k-1])
} else {
median = float32( max_nums[k-1] + max_nums[k]) /2
}
return
}
} else {
fmt.Println("数据不合法!")
return
}
}
}