524 字
3 分钟
LeetCode-4. 寻找两个正序数组的中位数
二分查找
给定两个大小分别为
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
思路
这一题我认为最主要的难点就是在时间复杂度O(log (m+n)),要求二分查找的情况下,如何在 A 里画一条分割线,在 B 里画一条分割线使得:
- 左边的元素总个数 等于 右边的元素总个数(如果是奇数,让左边多一个)。
- 左半边所有的数 都要 小于 右半边所有的数。
因为 A 和 B 本身就是有序的,所以 A 左边的数本来就 小于 右边的数。我们只需要保证的是:
A 左边最大的数 <= B 右边最小的数B 左边最大的数 <= A 右边最小的数
所以,我们可以像提线木偶般,在短的那个数组进行二分,为了保证左右元素总数各占一半,B 中的切分位置 就自动确定了,最后检查十字交叉条件即可(知道了思路,还是挺简单的)
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 { if len(nums1) > len(nums2) { return findMedianSortedArrays(nums2, nums1) }
m, n := len(nums1), len(nums2) left, right := 0, m totalLeft := (m + n + 1)/2
for left <= right { i := left + (right - left)/2 j := totalLeft - i
nums1LeftMax := math.MinInt if i > 0 { nums1LeftMax = nums1[i-1] }
nums1RightMin := math.MaxInt if i < m { nums1RightMin = nums1[i] }
nums2LeftMax := math.MinInt if j > 0 { nums2LeftMax = nums2[j-1] }
nums2RightMin := math.MaxInt if j < n { nums2RightMin = nums2[j] }
if nums1LeftMax <= nums2RightMin && nums2LeftMax <= nums1RightMin { if (n + m) % 2 == 1 { return float64(max(nums1LeftMax, nums2LeftMax)) }else { return float64(max(nums1LeftMax, nums2LeftMax) + min(nums1RightMin,nums2RightMin)) / 2.0 } }else if nums1LeftMax > nums2RightMin { right = i - 1 }else { left = i + 1 } } return 0.0} LeetCode-4. 寻找两个正序数组的中位数
https://sheep44044.github.io/posts/算法/二分查找/leetcode-4-寻找两个正序数组的中位数/