Java学习笔记
Leetcode刷题经验
热题HOT100
4、寻找两个正序数组的中位数
由于题目中要求时间复杂度需要降低到 O(log(m+n)),故可以采用二分查找,另外,根据中位数的定义,当两个正序数组的总长度m+n为奇数时,则其对应的中位数是两个有序数组中下标为 (m+n)/2的元素,当 m+n为偶数时,中位数是两个有序数组中下标为 (m+n)/2的元素以及下标为(m+n)/2+1元素的平均值。
解题思路:
假设两个有序数组分别是A 和B。要找到第 k个元素,我们可以比较 A [ k / 2 − 1 ] A[k/2−1] A[k/2−1] 和 B [ k / 2 − 1 ] B[k/2−1] B[k/2−1] ,其中 / 表示整数除法。由于 A [ k / 2 − 1 ] A[k/2−1] A[k/2−1] 和 B [ k / 2 − 1 ] B[k/2−1] B[k/2−1]的前面分别有 A [ 0.. k / 2 − 2 ] A[0..k/2−2] A[0..k/2−2]和 B [ 0.. k / 2 − 2 ] B[0..k/2−2] B[0..k/2−2],即 k/2−1 个元素,对于 A [ k / 2 − 1 ] A[k/2−1] A[k/2−1]和 B [ k / 2 − 1 ] B[k/2−1] B[k/2−1] 中的较小值,最多只会有 k − 2 k−2 k−2个元素比它小,而且它本身也不可能是第 k k k小元素,故可以将 A [ 0.. k / 2 − 1 ] A[0..k/2−1] A[0..k/2−1]这些元素全部删除即可。
因此,可归纳得出三种情况:
第一种情况:
如果 A [ k / 2 − 1 ] < B [ k / 2 − 1 ] A[k/2−1]<B[k/2−1] A[k/2−1]<B[k/2−1],则比 A [ k / 2 − 1 ] A[k/2−1] A[k/2−1] 小的数最多只有A的前 k / 2 − 1 k/2-1 k/2−1个数和B的前 k / 2 − 1 k/2-1 k/2−1个数,即比 A [ k / 2 − 1 ] A[k/2−1] A[k/2−1] 小的数最多只有 k − 2 k-2 k−2个,因此 A [ k / 2 − 1 ] A[k/2−1] A[k/2−1]不可能是第 k k k个数,那么从 A [ 0 ] A[0] A[0]到 A [ k / 2 − 1 ] A[k/2−1] A[k/2−1] 也都不可能是第 k k k个数,故可以全部排除。
第二种情况:
如果 A [ k / 2 − 1 ] > B [ k / 2 − 1 ] A[k/2−1]>B[k/2−1] A[k/2−1]>B[k/2−1],则同理可以排除 B [ 0 ] B[0] B[0]到 B [ k / 2 − 1 ] B[k/2−1] B[k/2−1]。
第三种情况:
如果 A [ k / 2 − 1 ] = B [ k / 2 − 1 ] A[k/2−1]=B[k/2−1] A[k/2−1]=B[k/2−1],则归入第一种情况处理即可。
此外,还需要注意以下三种特殊情况:
1、 如果 A [ k / 2 − 1 ] A[k/2−1] A[k/2−1] 或者 B [ k / 2 − 1 ] B[k/2−1] B[k/2−1]越界,那么我们可以选取对应数组中的最后一个元素。在这种情况下,我们必须根据排除数的个数减少 k k k的值,而不能直接将 k k k减去 k / 2 k/2 k/2。
2、 如果一个数组为空,说明该数组中的所有元素都被排除,我们可以直接返回另一个数组中第 k k k 小的元素。
3、 如果 k = 1 k=1 k=1,我们只要返回两个数组首元素的最小值即可。
由于每经历一轮循环就可以将查找范围减少一半,因此时间复杂度是 O ( l o g ( m + n ) ) O(log(m+n)) O(log(m+n)),而对应的空间复杂度为 O ( 1 ) O(1) O(1)。
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int length1=nums1.length,length2=nums2.length;
int totalLength=length1+length2;
if(totalLength%2==1){
int midIndex=totalLength/2;
double median=getKthElement(nums1,nums2,midIndex + 1);
return median;
}else{
int midIndex1=totalLength/2-1,midIndex2=totalLength/2;
double median=(getKthElement(nums1,nums2,midIndex1 + 1)+getKthElement(nums1, nums2, midIndex2 + 1)/2);
return median;
}
}
public double getKthElement(int[] nums1, int[] nums2,int k) {
int length1=nums1.length,length2=nums2.length;
int index1=0,index2=0;
while(true){
if(index1==length1){return nums2[index2 + k -1];}
if(index2==length2){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,length1)-1;
int newIndex2=Math.min(index2+half,length2)-1;
int point1=nums1[newIndex1],point2=nums2[newIndex1];
if(point1<=point2){
k-=(newIndex1-index1+1);
index1=newIndex1+1;
}else{
k-=(newIndex2-index2+1);
index2=newIndex2+1;
}
}
}
}
不过,该问题还有更好的解决办法,等弄懂了后期再进行更新!
欢迎大家交流,一起进步!