先简单看下问题:
给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n)) 。
看到该题目,我们大部分人第一反应就是,直接归并排序把nums1和nums2整合为1个数组,然后根据奇偶元素个数取中位数即可。
但是不要忽略了时间复杂度要求 O(log (m+n)) ,如果按照上述的思路,那么我们的时间复杂度为O(m+n)已经超过了以上要求。
所以,看到log我们其实可以猜测大概率是使用二分查找,那么我们具体应该如何操作呢?
- 首先我们计算一下两个数组的长度和totalLen,如果为奇数,我们取其第 totalLen/2 + 1 位的元素就是他的中位数(这里是从1开始数的)。
- 如果为偶数,我们就取第 totalLen/2 + 1 位的元素,和第totalLen/2位的元素再求中位数。
定义方法getKthElement(int[] nums1, int[] nums2, int k)查找两个数组中第k小的元素:
- 定义nums1和nums2的长度和初始下标。
- 对于一般情况,我们可以的取A[k / 2 - 1] ,B[k / 2 - 1] 的值:
当A[k / 2 - 1] < B[k / 2 - 1] 时,我们可以确认A[k / 2 - 1] 及之前的元素一定不是第k小的元素,所以将A[k / 2 - 1] 及之前的元素排除, 即 将下标 index1移动至当前A[k /2 - 1]下标 + 1处, k 减去排除的元素个数。
当B[k / 2 - 1] < A[k / 2 - 1] 时, 我们同样采取以上策略进行,将B[k / 2 - 1]及之前的元素排除。
当A[k / 2 - 1] == B[k / 2 - 1] 时, 我们可以将其归为上面两种情况之一进行即可。
然后我们要循环到什么时候停止呢,这时候就要想想边界条件时什么了:
- 当 k == 1时,我们循环停止,因为k代表的就是当前两数组集合中的第k小元素(排除掉之前元素后),这时候我们只要比较两数组当前下标元素的值,更小的元素即为所求。
- 当index1 == len1时,表面数组nums1已经排除了所有元素,这个适合,我们只要取num2排除之前元素后的第k - 1下标元素即为所求。
- 当index2 == len2时,表面数组nums2已经排除了所有元素,取num1当前下标往后k - 1的元素。
代码如下:
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int len1 = nums1.length;
int len2 = nums2.length;
int totalLen = len1 + len2;
if (totalLen % 2 == 1){
return getKthElement(nums1, nums2, totalLen / 2 + 1);
} else {
return (getKthElement(nums1, nums2, totalLen / 2 + 1) +
getKthElement(nums1, nums2, totalLen / 2)) * 0.5;
}
}
private int getKthElement(int[] nums1, int[] nums2, int k){
int len1 = nums1.length;
int len2 = nums2.length;
int index1 = 0, index2 = 0;
while (true){
if (index1 == len1){
return nums2[index2 + k - 1];
}
if (index2 == len2){
return nums1[index1 + k - 1];
}
if (k == 1){
return Math.min(nums1[index1], nums2[index2]);
}
int half = k / 2;
int newIndex1 = Math.min(index1 + half, len1) - 1;
int newIndex2 = Math.min(index2 + half, len2) - 1;
int pivot1 = nums1[newIndex1], pivot2 = nums2[newIndex2];
if (pivot1 <= pivot2){
k -= (newIndex1 - index1) + 1;
index1 = newIndex1 + 1;
} else {
k -= (newIndex2 - index2) + 1;
index2 = newIndex2 + 1;
}
}
}
}