Hard
题目描述
给定两个大小分别为 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 == mnums2.length == n0 <= m <= 10000 <= n <= 10001 <= m + n <= 2000-10^6 <= nums1[i], nums2[i] <= 10^6
解题思路
这道题要求在 O(log(m+n)) 时间复杂度内找到两个有序数组的中位数,关键在于利用二分查找思想。
核心思路:
分割数组:将两个数组分别分割成左右两部分,使得左半部分的所有元素都小于等于右半部分的所有元素,且左半部分的长度等于或比右半部分多1个元素。
二分查找:为了达到 O(log(m+n)) 的复杂度,我们在较短的数组上进行二分查找,确定分割点。设在 nums1 的 i 位置分割,在 nums2 的 j 位置分割,其中
j = (m+n+1)/2 - i。有效分割条件:
nums1[i-1] <= nums2[j](左边最大值 <= 右边最小值)nums2[j-1] <= nums1[i]
边界处理:当 i=0 或 i=m 时,需要特别处理边界情况。
推荐解法:二分查找 时间复杂度满足题目要求,代码简洁高效。另一种暴力解法是合并两个数组后找中位数,但时间复杂度为 O(m+n),不满足要求。
代码实现
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
if (nums1.size() > nums2.size()) {
return findMedianSortedArrays(nums2, nums1);
}
int m = nums1.size();
int n = nums2.size();
int left = 0, right = m;
while (left <= right) {
int i = (left + right) / 2;
int j = (m + n + 1) / 2 - i;
int maxLeft1 = (i == 0) ? INT_MIN : nums1[i-1];
int minRight1 = (i == m) ? INT_MAX : nums1[i];
int maxLeft2 = (j == 0) ? INT_MIN : nums2[j-1];
int minRight2 = (j == n) ? INT_MAX : nums2[j];
if (maxLeft1 <= minRight2 && maxLeft2 <= minRight1) {
if ((m + n) % 2 == 1) {
return max(maxLeft1, maxLeft2);
} else {
return (max(maxLeft1, maxLeft2) + min(minRight1, minRight2)) / 2.0;
}
} else if (maxLeft1 > minRight2) {
right = i - 1;
} else {
left = i + 1;
}
}
return 0.0;
}
};
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
if len(nums1) > len(nums2):
nums1, nums2 = nums2, nums1
m, n = len(nums1), len(nums2)
left, right = 0, m
while left <= right:
i = (left + right) // 2
j = (m + n + 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 (m + n) % 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
return 0.0
public class Solution {
public double FindMedianSortedArrays(int[] nums1, int[] nums2) {
if (nums1.Length > nums2.Length) {
return FindMedianSortedArrays(nums2, nums1);
}
int m = nums1.Length;
int n = nums2.Length;
int left = 0, right = m;
while (left <= right) {
int i = (left + right) / 2;
int j = (m + n + 1) / 2 - i;
int maxLeft1 = (i == 0) ? int.MinValue : nums1[i-1];
int minRight1 = (i == m) ? int.MaxValue : nums1[i];
int maxLeft2 = (j == 0) ? int.MinValue : nums2[j-1];
int minRight2 = (j == n) ? int.MaxValue : nums2[j];
if (maxLeft1 <= minRight2 && maxLeft2 <= minRight1) {
if ((m + n) % 2 == 1) {
return Math.Max(maxLeft1, maxLeft2);
} else {
return (Math.Max(maxLeft1, maxLeft2) + Math.Min(minRight1, minRight2)) / 2.0;
}
} else if (maxLeft1 > minRight2) {
right = i - 1;
} else {
left = i + 1;
}
}
return 0.0;
}
}
var findMedianSortedArrays = function(nums1, nums2) {
if (nums1.length > nums2.length) {
[nums1, nums2] = [nums2, nums1];
}
const m = nums1.length;
const n = nums2.length;
let left = 0;
let right = m;
while (left <= right) {
const partitionX = Math.floor((left + right) / 2);
const partitionY = Math.floor((m + n + 1) / 2) - partitionX;
const maxLeftX = partitionX === 0 ? -Infinity : nums1[partitionX - 1];
const minRightX = partitionX === m ? Infinity : nums1[partitionX];
const maxLeftY = partitionY === 0 ? -Infinity : nums2[partitionY - 1];
const minRightY = partitionY === n ? Infinity : nums2[partitionY];
if (maxLeftX <= minRightY && maxLeftY <= minRightX) {
if ((m + n) % 2 === 0) {
return (Math.max(maxLeftX, maxLeftY) + Math.min(minRightX, minRightY)) / 2;
} else {
return Math.max(maxLeftX, maxLeftY);
}
} else if (maxLeftX > minRightY) {
right = partitionX - 1;
} else {
left = partitionX + 1;
}
}
};
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(log(min(m,n))) | 在较短数组上进行二分查找 |
| 空间复杂度 | O(1) | 只使用常量额外空间 |
相关题目
- . Median of a Row Wise Sorted Matrix (Medium)