给定两个大小分别为 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
-106 <= nums1[i], nums2[i] <= 106
方法一:分治
本题限制了时间复杂度为
这里我们需要定义一个函数来在两个有序数组中找到第
首先,为了避免产生新的数组从而增加时间复杂度,我们使用两个变量 nums1
和 nums2
的起始位置。然后来处理一些边界问题,比如当某一个数组的起始位置大于等于其数组长度时,说明其所有数字均已经被淘汰了,相当于一个空数组了,那么实际上就变成了在另一个数组中找数字,直接就可以找出来了。还有就是如果 nums1
和 nums2
的起始位置
难点就在于一般的情况怎么处理?因为我们需要在两个有序数组中找到第 nums1
和 nums2
中查找第
最后是二分法的核心,比较这两个数组的第 midVal1
和 midVal2
的大小,如果第一个数组的第 nums1
中的前 nums1
的起始位置向后移动 nums2
中的前 nums2
的起始位置向后移动
实际是比较两个数组中的第
$\left \lfloor \frac{k}{2} \right \rfloor$ 个数字哪一个可能到达最后合并后排序数组中的第$k$ 个元素的位置,其中小的那个数字注定不可能到达,所以可以直接将小的元素对应的数组的前$\left \lfloor \frac{k}{2} \right \rfloor$ 个数字淘汰。
时间复杂度
class Solution:
def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
def findKth(i, j, k):
if i >= m:
return nums2[j + k - 1]
if j >= n:
return nums1[i + k - 1]
if k == 1:
return min(nums1[i], nums2[j])
midVal1 = nums1[i + k // 2 - 1] if i + k // 2 - 1 < m else inf
midVal2 = nums2[j + k // 2 - 1] if j + k // 2 - 1 < n else inf
if midVal1 < midVal2:
return findKth(i + k // 2, j, k - k // 2)
return findKth(i, j + k // 2, k - k // 2)
m, n = len(nums1), len(nums2)
left, right = (m + n + 1) // 2, (m + n + 2) // 2
return (findKth(0, 0, left) + findKth(0, 0, right)) / 2
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;
int left = (m + n + 1) / 2;
int right = (m + n + 2) / 2;
return (findKth(nums1, 0, nums2, 0, left) + findKth(nums1, 0, nums2, 0, right)) / 2.0;
}
private int findKth(int[] nums1, int i, int[] nums2, int j, int k) {
if (i >= nums1.length) {
return nums2[j + k - 1];
}
if (j >= nums2.length) {
return nums1[i + k - 1];
}
if (k == 1) {
return Math.min(nums1[i], nums2[j]);
}
int midVal1 = (i + k / 2 - 1 < nums1.length) ? nums1[i + k / 2 - 1] : Integer.MAX_VALUE;
int midVal2 = (j + k / 2 - 1 < nums2.length) ? nums2[j + k / 2 - 1] : Integer.MAX_VALUE;
if (midVal1 < midVal2) {
return findKth(nums1, i + k / 2, nums2, j, k - k / 2);
}
return findKth(nums1, i, nums2, j + k / 2, k - k / 2);
}
}
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int m = nums1.size();
int n = nums2.size();
int left = (m + n + 1) / 2;
int right = (m + n + 2) / 2;
return (findKth(nums1, 0, nums2, 0, left) + findKth(nums1, 0, nums2, 0, right)) / 2.0;
}
int findKth(vector<int>& nums1, int i, vector<int>& nums2, int j, int k) {
if (i >= nums1.size()) return nums2[j + k - 1];
if (j >= nums2.size()) return nums1[i + k - 1];
if (k == 1) return min(nums1[i], nums2[j]);
int midVal1 = i + k / 2 - 1 < nums1.size() ? nums1[i + k / 2 - 1] : INT_MAX;
int midVal2 = j + k / 2 - 1 < nums2.size() ? nums2[j + k / 2 - 1] : INT_MAX;
if (midVal1 < midVal2) return findKth(nums1, i + k / 2, nums2, j, k - k / 2);
return findKth(nums1, i, nums2, j + k / 2, k - k / 2);
}
};
func findMedianSortedArrays(nums1 []int, nums2 []int) float64 {
m, n := len(nums1), len(nums2)
left, right := (m+n+1)/2, (m+n+2)/2
var findKth func(i, j, k int) int
findKth = func(i, j, k int) int {
if i >= m {
return nums2[j+k-1]
}
if j >= n {
return nums1[i+k-1]
}
if k == 1 {
return min(nums1[i], nums2[j])
}
midVal1 := math.MaxInt32
midVal2 := math.MaxInt32
if i+k/2-1 < m {
midVal1 = nums1[i+k/2-1]
}
if j+k/2-1 < n {
midVal2 = nums2[j+k/2-1]
}
if midVal1 < midVal2 {
return findKth(i+k/2, j, k-k/2)
}
return findKth(i, j+k/2, k-k/2)
}
return (float64(findKth(0, 0, left)) + float64(findKth(0, 0, right))) / 2.0
}
func min(a, b int) int {
if a < b {
return a
}
return b
}