普通解法
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {//合并两个有序数组int n = nums1.length;int m = nums2.length;int[] nums = new int[m + n];int index = nums.length;while (m > 0 && n > 0) {if (nums1[n - 1] >= nums2[m - 1]) {nums[--index] = nums1[--n];} else {nums[--index] = nums2[--m];}}while (n > 0) {nums[--index] = nums1[--n];}while (m > 0) {nums[--index] = nums2[--m];}//找中位数if ((nums.length & 1) == 0) {return (nums[nums.length/ 2] + nums[nums.length/ 2 - 1]) / 2.0;} else {return nums[nums.length/ 2];}}
最优解法
https://leetcode-cn.com/problems/median-of-two-sorted-arrays/
- int _findKthNum ( _int[] arr1, int[] arr2, _int _kth )
- int _getUpMedian ( _int[] A, int _s1, _int _e1, _int[] B, _int _s2, _int _e2 )
- 函数getUpMedian 两个数组等长, 找上中位数
- 1)偶数长度
- 分三种情况, mid == mid’ mid > mid’ mid < mid’
- 然后看哪些数不可能是上中位数,然后排除, 然后剩下的两个等长的继续迭代
- 分三种情况, mid == mid’ mid > mid’ mid < mid’
- 2)奇数长度
- 也是跟上边一样分三种情况,不过具体某些情况需要手动扣掉一些数,保证长度一样然后能迭代
- 1)偶数长度
/*A[s1...e1]B[s2...e2]这两段一定等长且都有序求这两段整体的上中位数,上中位数值返回*/public static int getUpMedian(int[] A, int s1, int e1, int[] B, int s2, int e2) {int mid1 = 0;int mid2 = 0;// 每个数组至少两个数while (s1 < e1) {mid1 = (s1 + e1) >> 1;mid2 = (s2 + e2) >> 1;if (A[mid1] == B[mid2]) {return A[mid1];}if (((e1 - s1 + 1) & 1) == 0) { // 偶数长度// A[0, 1, 2, 3]// B[0‘, 1’, 2‘, 3’]// 里面的值代表下标// 上中位数就是第4位数if (A[mid1] > B[mid2]) { // 2, 3, 0', 1'排除e1 = mid1;s2 = mid2 + 1;} else { //反之e2 = mid2;s1 = mid1 + 1;}} else { // 奇数长度// A[0, 1, 2, 3, 4]// B[0‘, 1’, 2‘, 3’, 4']// 上中位数就是第5位数if (A[mid1] > B[mid2]) { // 2, 3, 4, 0', 1'排除if (B[mid2] >= A[mid1 - 1]) { // 手动抠一个, 若成立则找到了答案,返回return B[mid2];}//不成立的话,那我们的迭代潜台词(两个数组等长)就可以维持下去了e1 = mid1 - 1;s2 = mid2 + 1;} else { //反之if (A[mid1] >= B[mid2 - 1]) {return A[mid1];}e2 = mid2 - 1;s1 = mid1 + 1;}}}// 此时退出了while循环,此刻条件s1 == e1, while循环里面没找到答案// 说明每个数组此刻只剩一个数// 那么上中位数就返回其中比较小的一个即可return Math.min(A[s1], B[s2]);}
- 函数findKthNum ,两个数组可以不等长, 找第K小的数
- 分三种情况
- 1)1 ≤ K ≤ 短数组长度
- 直接用算法原型getUpMedian
- 2)短数组长度 < k ≤ 长数组长度
- 短数组中所有的数都有可能- 长数组中的数部分有可能- 在长数组中可能的数部分中,手动扣掉一个后,才能用上我们的算法原型
- 3)长数组长度<K < 两个数组的总长度
- 特别注意- 需要手动扣两个- 排除的个数 + 。。。 = Kth


- 主函数调用 double _findMedianSortedArrays(_int[] nums1, int[] nums2) {
- 判断两个数组总长度是奇数还是偶数,若是偶数就调用两次findKthNum函数然后平均下,若是奇数就调用一次findKthNum
//两个数组不等长, 找第K小的数public static int findKthNum(int[] arr1, int[] arr2, int kth) {int[] longs = arr1.length >= arr2.length ? arr1 : arr2;int[] shorts = arr1.length < arr2.length ? arr1 : arr2;int l = longs.length;int s = shorts.length;if (kth <= s) { //直接调算法原型return getUpMedian(arr1, 0, kth - 1, arr2, 0, kth - 1);} else if (kth > s && kth <= l) {// 自己举例子,然后排除掉一些数, 最后再扣掉一个数,若是答案则返回,// 否则,就可以使得两个范围的长度相等,调算法原型if (longs[kth - s - 1] >= shorts[s - 1]) {return longs[kth - s - 1];}return getUpMedian(shorts, 0, s - 1, longs, kth - s, kth - 1);} else {// 自己举例子,然后排除掉一些数, 最后再扣掉二个数,若是答案则返回,// 否则,就可以使得两个范围的长度相等,调算法原型if (shorts[kth - l - 1] >= longs[l - 1]) {return shorts[kth - l - 1];}if (longs[kth - s - 1] >= shorts[s - 1]) {return longs[kth - s - 1];}return getUpMedian(shorts, kth - l, s - 1, longs, kth - s, l - 1);}}
- 总代码
```java
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
} //两个数组不等长, 找第K小的数 public static int findKthNum(int[] arr1, int[] arr2, int kth) {int size = nums1.length + nums2.length;boolean even = (size & 1) == 0;if (nums1.length != 0 && nums2.length != 0) {if (even) {return (double) (findKthNum(nums1, nums2, size / 2) + findKthNum(nums1, nums2, size / 2 + 1)) / 2;} else {return findKthNum(nums1, nums2, size / 2 + 1);}} else if (nums1.length != 0) {if (even) {return (double) (nums1[(size - 1) / 2] + nums1[size / 2]) / 2;} else {return nums1[size / 2];}} else if (nums2.length != 0) {if (even) {return (double) (nums2[(size - 1) / 2] + nums2[size / 2]) / 2;} else {return nums2[size / 2];}} else {return 0;}
}int[] longs = arr1.length >= arr2.length ? arr1 : arr2; int[] shorts = arr1.length < arr2.length ? arr1 : arr2; int l = longs.length; int s = shorts.length; if (kth <= s) { //直接调算法原型 return getUpMedian(arr1, 0, kth - 1, arr2, 0, kth - 1); } else if (kth > s && kth <= l) { // 自己举例子,然后排除掉一些数, 最后再扣掉一个数,若是答案则返回, // 否则,就可以使得两个范围的长度相等,调算法原型 if (longs[kth - s - 1] >= shorts[s - 1]) { return longs[kth - s - 1]; } return getUpMedian(shorts, 0, s - 1, longs, kth - s, kth - 1); } else { // 自己举例子,然后排除掉一些数, 最后再扣掉二个数,若是答案则返回, // 否则,就可以使得两个范围的长度相等,调算法原型 if (shorts[kth - l - 1] >= longs[l - 1]) { return shorts[kth - l - 1]; } if (longs[kth - s - 1] >= shorts[s - 1]) { return longs[kth - s - 1]; } return getUpMedian(shorts, kth - l, s - 1, longs, kth - s, l - 1); }
/*
A[s1...e1]
B[s2...e2]
这两段一定等长且都有序
求这两段整体的上中位数,上中位数值返回
*/
public static int getUpMedian(int[] A, int s1, int e1, int[] B, int s2, int e2) {
int mid1 = 0;
int mid2 = 0;
// 每个数组至少两个数
while (s1 < e1) {
mid1 = (s1 + e1) >> 1;
mid2 = (s2 + e2) >> 1;
if (A[mid1] == B[mid2]) {
return A[mid1];
}
if (((e1 - s1 + 1) & 1) == 0) { // 偶数长度
// A: 1, 2, 3, 4,
// B: 1‘, 2', 3', 4'
// 上面的数字是代表编号(第几个数)
// 上中位数就是第4位数
if (A[mid1] > B[mid2]) { // 2, 3, 0', 1'排除
e1 = mid1;
s2 = mid2 + 1;
} else { //反之
e2 = mid2;
s1 = mid1 + 1;
}
} else { // 奇数长度
// A: 1, 2, 3, 4, 5
// B: 1‘, 2', 3', 4', 5'
// 上面的数字是代表编号(第几个数)
// 上中位数就是第5位数
if (A[mid1] > B[mid2]) { // 2, 3, 4, 0', 1'排除
if (B[mid2] >= A[mid1 - 1]) { // 手动抠一个, 若成立则找到了答案,返回
return B[mid2];
}
//不成立的话,那我们的迭代潜台词(两个数组等长)就可以维持下去了
e1 = mid1 - 1;
s2 = mid2 + 1;
} else { //反之
if (A[mid1] >= B[mid2 - 1]) {
return A[mid1];
}
e2 = mid2 - 1;
s1 = mid1 + 1;
}
}
}
// 此时退出了while循环,此刻条件s1 == e1, while循环里面没找到答案
// 说明每个数组此刻只剩一个数
// 那么上中位数就返回其中比较小的一个即可
return Math.min(A[s1], B[s2]);
}
```
时间复杂度

