Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情。
题目描述:
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。
示例 1:
输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:
输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
提示:
nums1.length == m
nums2.length == n
0 <= m <= 1000
0 <= n <= 1000
1 <= m + n <= 2000
-10 的 6次方 <= nums1[i], nums2[i] <= 10 的 6次方
思路分析:
-
计算两个数组的长度和 和 循环截止的下标。
长度和的结果是奇数,则中位数是中间的单个值,循环截止的下标为中间的单个下标;结果是偶数,则中位数是位于中间的两个元素的平均值,循环截止的下标为中间两个下标中较大的下标。 -
定义当前值、上一个值和两个数组循环用的下标的三个变量。
-
循环处理,下标从 0 到循环截止的下标。
-
当前值赋值给上一个值。
-
如果数组 1 里和数组 2 里对应的下标位置都有值,则比较大小后,小的值设置给当前值,同时循环用的下标加 1 。
-
如果只有一个数组里在对应的下标位置有值,则设置给当前值,同时循环用的下标加 1 。
-
4。 1 中计算长度和的结果是奇数时,返回当前值;为偶数时,则返回当前值和上一个值的平均值。
AC 代码:
golang :
// 寻找两个正序数组的中位数
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
// 数组元素个数
ln1 := len(nums1)
ln2 := len(nums2)
ln := ln1 + ln2
// 中间下标
mid := 0
isEven := false // 数组元素总个数是否为偶数标志
if ln%2 == 1 {
mid = (ln - 1) / 2
} else {
mid = ln / 2
isEven = true
}
m := 0
n := 0
current := 0
prev := 0
for i := 0; i <= mid; i++ {
// 上一个值
prev = current
if m < ln1 && n < ln2 {
// 比较后小的值设置给当前值
if nums1[m] < nums2[n] {
current = nums1[m]
m = m + 1
} else {
current = nums2[n]
n = n + 1
}
} else if m < ln1 {
// 当前值
current = nums1[m]
m = m + 1
} else if n < ln2 {
// 当前值
current = nums2[n]
n = n + 1
}
}
if isEven {
// 元素总个数为偶数时,取当前值和上一个值的和的平均值
return float64(current+prev) / 2
} else {
// 元素总个数为奇数时,取当前值
return float64(current)
}
return 0
}
总结:
-
循环时最多只用到当前值和上一个值。
一开始的作法是把数组1和数组2的元素添加到另外一个切片中,结束循环的条件相同,最后再取中位数的值。
这种方法有频繁的切片操作,耗时也耗内存。 -
一开始还加上了对数组1和数组2里元素个数是 0 还是 1 的判断,现在的循环已经包括这两种情况,判断画蛇添足,而且大部分的测试用例,肯定是元素个数大于 1 的,所以效率也不高。
-
取上一个值的地方,也走了弯路,用标志来记录上次用的是哪个数组的值。
后来看了高手的答案后才发现,在每次循环开始的地方,把当前值的值设置给上一个值就可以了。
又是大脑短路!囧!