持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情
题目描述
题目释义
- 给定数组nums1和nums2
- 求这两个数组的中位数
题目要求算法时间复杂度为
O(log (m+n))
解题思路
数组的中位数,最简单的方法是将两个数组进行合并,然后再进行排序,然后再取中位数。但是通过这种方法解题,算法时间复杂度为O (m+n)不满足条件。
求数组的中位数:
- 如果数组大小为奇数,则中位数的排序为(length+1)/2;
- 如果数组大小为偶数,则中位数的排序为(length/2+length/2+1)/2 总的来说数组大小为奇数,需要获取的是排序为(length+1)/2的值;如果为偶数,则需要获取排序为length/2和length/2+1的值。
求数组的指定排序位置的数值,而且要使时间复杂度为O(log (m+n)),就应该想到用二分法解题。
二分值应该是需要求的排序数,假设这个值为k,则第一次先查询两个数组位置为k/2的值,比较它们的大小,如果nums1[k/2]>nums2[k/2],则数组2的查询范围缩小,即nums2前面的数一定不满足中位数的条件。依次类推,截止条件应该为其中一个数组到数组尾端(根据当前k和已排除了的数组长度获得中位数值)或k==1即找到中位数位置直接返回。
代码实现:
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int n = nums1.length;
int m = nums2.length;
double res;
if ((m + n ) % 2 == 0){
//偶数
res = (getKth(nums1,0,n-1,nums2,0,m-1,(m+n)/2)+getKth(nums1,0,n-1,nums2,0,m-1,(m+n)/2+1))*0.5;
}else {
//奇数
res = getKth(nums1,0,n-1,nums2,0,m-1,(m+n+1)/2);
}
return res;
}
private int getKth(int[] nums1, int start1, int end1, int[] nums2, int start2, int end2, int k) {
//交换数组位置,让长数组始终位于第二位
if (end1-start1 > end2-start2){
return getKth(nums2, start2, end2, nums1, start1, end1, k);
}
//如果短数组到尾端,则直接返回长数组的位置
if (end1<start1){
return nums2[start2 + k - 1];
}
//如果k达到1,说明已经找到二分点
if (k == 1){
return Math.min(nums1[start1], nums2[start2]);
}
int i = start1 + Math.min(end1-start1+1, k / 2) - 1;
int j = start2 + Math.min(end2-start2+1, k / 2) - 1;
if (nums1[i] > nums2[j]) {
//第一个数组的值大于第二个数组,则直接将第二个数组的前移
return getKth(nums1, start1, end1, nums2, j + 1, end2, k - (j - start2 + 1));
}
else {
//第二个数组的值大于第一个数组,则直接将第一个数组的前移
return getKth(nums1, i + 1, end1, nums2, start2, end2, k - (i - start1 + 1));
}
}