以下三道题环环相扣,前面的题的解法可以用来解后面的题。先解决问题1,然后在问题1的基础上解决问题2,再在问题2的基础上解决问题3。
问题1
解题方法有多种
- 放在一起,整体排序
- 按照归并排序的“一趟合并”过程,但不做真的合并,只移动指针,找到上中位数即返回
- 二分
- 划分数组
下面具体分析最后一种 “划分数组” 的解题方法。已知两数组等长且有序,先分析可能出现的多种情况,
- 数组的长度为0
- 不符合题目给定的输入数据限制
- 数组的长度为1
- 较小的那个值就是上中位数
- 数组的长度大于等于2
- 中值相等
- 数组的长度为奇数 设一个数组为a=[0,1,2,3,4],另一个为a'=[0',1',2',3',4']。注意,数组里的数是元素的索引(从0开始),不是具体的值。“中值相等”,那么就有2==2'。显然,此时上中位数就是2(或者2')。
- 数组的长度为偶数 设一个数组a=[0,1,2,3],另一个数组a'=[0',1',2',3']。“中值相等”,那么就有1==1'。显然,此时上中位数就是1(或者1')。
- 一个中值大于另一个中值
- 数组的长度为奇数
- 数组的长度为偶数
- 一个中值小于另一个中值(这种情况和前一种是类似的)
- 数组的长度为奇数
- 数组的长度为偶数
- 中值相等
问题2
思路:
问题3
思路:根据有序数组的性质,不断抛弃不存在所需数据的区间。
这确实是一道难题,需要细致分析多种情况。最好的办法就是在纸上分情况推演。
// 入口函数
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
l1 := len(nums1)
l2 := len(nums2)
if l1 == 0 && l2 == 0 {
panic("nums1 and nums2 are all empty")
}
if l1 == 0 {
return getMedian(nums2)
}
if l2 == 0 {
return getMedian(nums1)
}
// l1 > 0 && l2 > 0
l := l1+l2
if l&1 != 0 {
return float64(getKthSmallest(nums1, nums2, l>>1+1))
}
return (float64(getKthSmallest(nums1, nums2, l>>1))+float64(getKthSmallest(nums1, nums2, l>>1+1)))/2
}
// 找到两个有序数组的第k小的数
// k >= 1 && k <= len(a1)+len(a2)
func getKthSmallest(a1, a2 []int, k int) int {
var (
l1 = len(a1)
l2 = len(a2)
)
if k < 1 || k > l1+l2 {
panic("k is invalid")
}
var (
sl = l1 // 短数组的长度
sa = a1 // 短数组
ll = l2 // 长数组的长度
la = a2 // 长数组
)
if l1 > l2 {
sl = l2
sa = a2
ll = l1
la = a1
}
if k <= sl {
return getUpMedian(a1[:k], a2[:k])
}
if k > ll {
li := k-sl-1 // 长数组的索引
if la[li] >= sa[sl-1] {
return la[li]
}
si := k-ll-1
if sa[si] >= la[ll-1] {
return sa[si]
}
return getUpMedian(sa[si+1:], la[li+1:])
}
// k > sl && k <= ll
li := k-sl-1 // 长数组索引
if la[li] >= sa[sl-1] {
return la[li]
}
if la[k-1] <= sa[0] {
return la[k-1]
}
return getUpMedian(sa, la[li+1:k])
}
// 找到两个长度相等的有序数组的上中位数
func getUpMedian(a1, a2 []int) int {
var (
l1 = len(a1)
l2 = len(a2)
)
if l1 != l2 {
panic("len(a1) != len(a2)")
}
var (
b1 int
e1 = l1-1
b2 int
e2 = l2-1
)
for b1 < e1 && b2 < e2 {
m1 := b1+(e1-b1)>>1
m2 := b2+(e2-b2)>>1
l := e1-b1+1
if a1[m1] == a2[m2] {
return a1[m1]
}
if a1[m1] > a2[m2] {
if l&1 != 0 {
e1 = m1
b2 = m2
} else {
e1 = m1
b2 = m2+1
}
} else {
if l&1 != 0 {
b1 = m1
e2 = m2
} else {
b1 = m1+1
e2 = m2
}
}
}
return min(a1[b1], a2[b2])
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
// 计算一个有序数组的中位数
func getMedian(nums []int) float64 {
l := len(nums)
if l == 0 {
panic("nums is empty")
}
if l&1 != 0 {
return float64(nums[l>>1])
}
return (float64(nums[l>>1-1])+float64(nums[l>>1]))/2
}
时间复杂度,空间复杂度。