寻找两个正序数组的中位数
首先先判断两个数组的总长度是奇数还是偶数
奇数的话返回中间那个,偶数的话要返回中间两个的均值.
然后核心是寻找两个数组中第K大的元素 所以主要是后面那个方法!!!
public class Solution046 {
public static void main(String[] args) {
int[] nums1 = new int[]{1,2}, nums2 = new int[]{3,4};
System.out.println(findMedianSortedArrays(nums1,nums2));
}
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
int total = nums1.length + nums2.length;
if (total % 2 == 1) {//一共奇数个元素 所以直接返回中间那个就行
return fingKthElement(nums1, nums2, total / 2 + 1);
} else {//一共偶数个元素 要返回中间两个的平均值
int mid = total / 2;
double ans = (fingKthElement(nums1, nums2, mid) + fingKthElement(nums1, nums2, mid + 1)) / 2.0;
return ans;
}
}
//寻找两个数组中第K大的元素
public static int fingKthElement(int[] nums1, int[] nums2, int k) {
/*基本思想:要寻找第K大的元素 分别判断nums1[k/2-1]和nums2[k/2-1]的大小
如果nums1[k/2-1]<=nums2[k/2-1] 那么就算nums2的前k/2-1个元素都比你小 你也不过是第(k/2-1)+1+(k/2-1)=k-1个元素 所以可以排除了
这样的话 就可以nums1就在[k/2+1,len1]之间查找 nums2没变 然后现在要找的就是第k-((k/2-1)+1)个元素了
反之亦然!
* */
int len1 = nums1.length, 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(len1, index1 + half) - 1;//要判断一下当前的index1+half是否已经超出了数组的边界 如果超出的话 只能使用数组的最后一个元素进行比较
int newindex2 = Math.min(len2, index2 + half) - 1;
if (nums1[newindex1] <= nums2[newindex2]) {//说明newindex1之前(包括newindex1)的元素都不可能是答案 可以排除了
k = k - (newindex1 - index1 + 1);
index1 = newindex1 + 1;
} else {
k = k - (newindex2 - index2 + 1);
index2 = newindex2 + 1;
}
}
}
}
整个算法的核心其实就在寻找两个数组中第K大的元素
这里的基本思想是:
- 要寻找第K大的元素 分别判断nums1[k/2-1]和nums2[k/2-1]的大小
- 如果nums1[k/2-1]<=nums2[k/2-1] 那么就算nums2的前k/2-1个元素都比你小 你也不过是第(k/2-1)+1+(k/2-1)=k-1个元素 所以可以排除了
- 这样的话 就可以nums1就在[k/2+1,len1]之间查找 nums2没变 然后现在要找的就是第k-((k/2-1)+1)个元素了
- 反之亦然!
//寻找两个数组中第K大的元素
public static int fingKthElement(int[] nums1, int[] nums2, int k) {
/*基本思想:要寻找第K大的元素 分别判断nums1[k/2-1]和nums2[k/2-1]的大小
如果nums1[k/2-1]<=nums2[k/2-1] 那么就算nums2的前k/2-1个元素都比你小 你也不过是第(k/2-1)+1+(k/2-1)=k-1个元素 所以可以排除了
这样的话 就可以nums1就在[k/2+1,len1]之间查找 nums2没变 然后现在要找的就是第k-((k/2-1)+1)个元素了
反之亦然!
* */
int len1 = nums1.length, 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(len1, index1 + half) - 1;//要判断一下当前的index1+half是否已经超出了数组的边界 如果超出的话 只能使用数组的最后一个元素进行比较
int newindex2 = Math.min(len2, index2 + half) - 1;
if (nums1[newindex1] <= nums2[newindex2]) {//说明newindex1之前(包括newindex1)的元素都不可能是答案 可以排除了
k = k - (newindex1 - index1 + 1);
index1 = newindex1 + 1;
} else {
k = k - (newindex2 - index2 + 1);
index2 = newindex2 + 1;
}
}
}