思路:
第一种方式双指针,只要排序一半数组的就行,那么就找到中位数。两个指针谁小移动谁。
1、两个都是有序数组,那么中位数就是合并成一个新的有序数组的中位数
2、只要排序到新数组长度的一半就可以得到中位数。因为我们不需要有序的数组,所以新建一个数组来记录。
代码如下:
class Solution {
// 定义一个函数,接收两个整数数组作为参数
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
// 初始化两个指针,分别指向两个数组的开始
int aIndex = 0;
int bIndex = 0;
// value 用于记录当前访问的元素,before 用于记录上一个访问的元素
int value = 0;
int before = 0;
// 循环至两数组长度之和的一半,因为中位数就在这个位置
for (int i = 0; i <= (nums1.length + nums2.length) / 2; i++) {
before = value; // 更新前一个元素
// 比较两个数组当前元素的大小,以决定从哪个数组取元素
if (aIndex < nums1.length && bIndex < nums2.length && nums1[aIndex] <= nums2[bIndex]) {
value = nums1[aIndex++]; // 取 nums1 的元素,并将 aIndex 加 1
} else {
// 如果 nums1 已全部访问完,只能从 nums2 取元素
if (aIndex >= nums1.length) {
value = nums2[bIndex++]; // 取 nums2 的元素,并将 bIndex 加 1
} else if (bIndex >= nums2.length) { // 如果 nums2 已全部访问完,只能从 nums1 取元素
value = nums1[aIndex++];
} else { // 否则从 nums2 取元素
value = nums2[bIndex++];
}
}
}
// 根据两数组长度之和判断是奇数还是偶数
if ((nums1.length + nums2.length) % 2 == 0) {
// 如果是偶数,中位数是中间两个数的平均值
return (value + before) / 2.0;
} else {
// 如果是奇数,中位数是中间的那个数
return value * 1.0;
}
}
}
第二种方式:改成求第k小的数。那么中位数就是第mid小的数。这个求第K小的数据就可以使用二分的方式。
public class Solution {
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
int size = nums1.length + nums2.length;
int mid = findKthNum(nums1, nums2, size / 2+1);
if (size%2==0){
int upMid = findKthNum(nums1, nums2, size / 2);
return (upMid+mid)/2.0;
}else {
return mid*1.0;
}
}
public static int findKthNum(int[] arr1, int[] arr2, int kth) {
int len1 = arr1.length, len2 = arr2.length;
// 检查k是否为有效值
if (kth > len1 + len2 || kth < 1) {
return Integer.MAX_VALUE; // 返回一个错误码,比如-1,表示输入不合法
}
int index1 = 0, index2 = 0; // 初始化两个数组的指针
while (true) {
// 边界情况
if (index1 == len1) {
return arr2[index2 + kth - 1]; // arr1已经全部考虑过,直接从arr2中取值
}
if (index2 == len2) {
return arr1[index1 + kth - 1]; // arr2已经全部考虑过,直接从arr1中取值
}
if (kth == 1) {
return Math.min(arr1[index1], arr2[index2]); // 如果kth为1,最小的数即为两数组当前指针的最小值
}
// 正常情况,通过二分的方式减少搜索范围
int halfK = kth / 2;
int newIndex1 = Math.min(index1 + halfK, len1) - 1; // 计算新的指针位置,不越界
int newIndex2 = Math.min(index2 + halfK, len2) - 1;
int pivot1 = arr1[newIndex1], pivot2 = arr2[newIndex2];
if (pivot1 <= pivot2) {
// pivot1较小或相等,舍弃arr1中index1到newIndex1的部分 就是说这部分不可能成为第k小数,但是肯定比第k小还要小,
//那么这部分有多少个数呢?newIndex1-index+1 那么就是求 k减去这部分的 小值
kth = kth - (newIndex1 - index1 + 1);
//重新设置index1
index1 = newIndex1 + 1;
} else {
// pivot2较小,舍弃arr2中index2到newIndex2的部分 同上
kth -= (newIndex2 - index2 + 1);
//重新设置index2
index2 = newIndex2 + 1;
}
}
// 由于逻辑保证了函数能够在循环中返回有效值,因此这里不需要额外的return语句
}
}