这道算法题来自LeetCode的经典题目"寻找两个正序数组的中位数"。给定两个大小分别为m和n的正序(非递减)数组nums1和nums2,要求找出这两个数组合并后的中位数。题目要求算法的时间复杂度应为O(log(m+n))。
在实际开发中,这类问题常见于以下场景:
最直观的解法是将两个数组合并后排序,然后直接取中位数:
python复制def findMedianSortedArrays(nums1, nums2):
merged = sorted(nums1 + nums2)
n = len(merged)
if n % 2 == 1:
return merged[n//2]
else:
return (merged[n//2-1] + merged[n//2])/2
这种方法虽然简单,但时间复杂度为O((m+n)log(m+n)),不满足题目要求。
利用两个数组已经有序的特性,可以使用双指针进行归并:
python复制def findMedianSortedArrays(nums1, nums2):
i = j = 0
merged = []
while i < len(nums1) and j < len(nums2):
if nums1[i] < nums2[j]:
merged.append(nums1[i])
i += 1
else:
merged.append(nums2[j])
j += 1
merged += nums1[i:]
merged += nums2[j:]
n = len(merged)
if n % 2 == 1:
return merged[n//2]
else:
return (merged[n//2-1] + merged[n//2])/2
这种方法的时间复杂度是O(m+n),虽然比暴力法好,但仍未达到题目要求。
要达到O(log(m+n))的时间复杂度,必须使用二分查找的思想。核心思路是:
python复制def findMedianSortedArrays(nums1, nums2):
if len(nums1) > len(nums2):
nums1, nums2 = nums2, nums1
m, n = len(nums1), len(nums2)
left, right = 0, m
total = m + n
while left <= right:
i = (left + right) // 2
j = (total + 1) // 2 - i
max_left1 = float('-inf') if i == 0 else nums1[i-1]
min_right1 = float('inf') if i == m else nums1[i]
max_left2 = float('-inf') if j == 0 else nums2[j-1]
min_right2 = float('inf') if j == n else nums2[j]
if max_left1 <= min_right2 and max_left2 <= min_right1:
if total % 2 == 1:
return max(max_left1, max_left2)
else:
return (max(max_left1, max_left2) + min(min_right1, min_right2)) / 2
elif max_left1 > min_right2:
right = i - 1
else:
left = i + 1
需要特别注意以下边界情况:
完整的测试应包含以下情况:
python复制test_cases = [
([1,3], [2], 2.0),
([1,2], [3,4], 2.5),
([0,0], [0,0], 0.0),
([], [1], 1.0),
([2], [], 2.0),
([1,3,5,7], [2,4,6,8], 4.5),
([1,2,3,4,5], [6,7,8,9,10], 5.5)
]
该算法思想还可应用于:
提示:在面试中遇到此类问题时,建议先阐述暴力解法,再逐步优化到最优解,展示完整的思考过程。