找第K位小数 O(log(m+n))
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
int len1 = nums1.length;
int len2 = nums2.length;
int k1 = (len1 + len2 + 1) / 2;
int k2 = (len1 + len2 + 2) / 2;
return (getKth(nums1, 0, len1 - 1, nums2, 0, len2 - 1, k1)
+ getKth(nums1, 0, len1 - 1, nums2, 0, len2 - 1, k2)) * 0.5;
}
private static int getKth(int[] nums1, int start1, int end1, int[] nums2, int start2, int end2, int k) {
int len1 = end1 - start1 + 1;
int len2 = end2 - start2 + 1;
//方便K=1时,返回结果
if(len1 > len2){
return getKth(nums2,start2,end2,nums1,start1,end1,k);
}
//num1空了,只要动nums2就行
if(len1 == 0) return nums2[start2 + k - 1];
if(k==1) return Math.min(nums1[start1],nums2[start2]);
int i = start1 + Math.min(len1, k / 2) - 1;
int j = start2 + Math.min(len2, 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));
}
}
划分数组,两分法 O(log(min(m,n))
public static double findMedianSortedArrays2(int[] nums1, int[] nums2) {
if (nums1.length > nums2.length) {
int[] temp = nums1;
nums1 = nums2;
nums2 = temp;
}
int n = nums1.length;
int m = nums2.length;
//得到左部分长度,向上取整,奇数多一个
int totalLeft = (n + m + 1) / 2;
// 在 nums1 的区间 [0, n] 里查找恰当的分割线,
// 使得 nums1[i - 1] <= nums2[j] && nums2[j - 1] <= nums1[i],等价于nums[0,n]中找到最大的i
int left = 0;
int right= n;
while(left < right){
int i = (left + right + 1) /2;
int j = totalLeft - i;
if(nums1[i-1] > nums2[j]){
//左移
right = i-1;
}else{
//右移
left = i;
}
}
int i = left;
int j = totalLeft - i;
int nums1LeftMax = i==0?Integer.MIN_VALUE:nums1[i-1];
int nums2LeftMax = j==0?Integer.MIN_VALUE:nums2[j-1];
int nums1RightMin= i==n?Integer.MAX_VALUE:nums1[i];
int nums2RightMin= j==m?Integer.MAX_VALUE:nums2[j];
if((n+m%2)==1){
return Math.max(nums1LeftMax,nums2LeftMax);
}else{
return (double)(Math.max(nums1LeftMax,nums2LeftMax) + Math.min(nums1RightMin,nums2RightMin)) /2;
}
}