给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
示例 1:
1 2 3 4
| nums1 = [1, 3] nums2 = [2]
则中位数是 2.0
|
示例 2:
1 2 3 4
| nums1 = [1, 2] nums2 = [3, 4]
则中位数是 (2 + 3)/2 = 2.5
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
| /* 解题思路: 由于这两个数组都是有序数组,如果我们从下标为i的地方把nums1数组分为两半,左边的数肯定比nums1[i]小,右边比nums2[i]大 同理把nums2数组从下标为j的地方分为两半 left | right nums1[0], nums1[1], ..., nums1[i-1] | nums1[i], nums1[i+1], ..., nums1[m-1] nums2[0], nums2[1], ..., nums2[j-1] | nums2[j], nums2[j+1], ..., nums2[n-1] 那只要满足两个条件,我们就可以顺利找到中位数 1. len(left)==len(right) 相当于 i+j=m-i+n-j 2. min(right) >= max(left) 相当于 nums2[j] >= nums2[i-1] && nums1[i] >= nums2[j-1] 对于第一个条件: 我们可以推出j = (m + n) / 2 - i,当i的值确定,j的值就确定了,也就是说我们只要把i的值确定下来满足第二个条件就行 对于第二个条件: 我们需要满足 nums2[j] >= nums1[i-1] && nums1[i] >= nums2[j-1],不满足的条件有两种: 1. nums2[j] < nums1[i-1],说明i的值太大了,你想想nums1[i]的值肯定大于nums1[i-1],如果i继续加大,条件永远无法满足,所以要减小i 2. nums1[i] < nums2[j-1],说明i的值太小了,需要加大i的值 最后我们再看看满足条件nums2[j] >= nums1[i-1] && nums1[i] >= nums2[j-1]是怎么得到中位 max(left) = max(nums1[i-1], nums2[j-1]) min(right) = min(nums1[i], nums1[j]) 如果数组之和是偶数,中位数 = (max(left) + min(right)) / 2 如果数组之和是奇数,中位数 = max(left)或者min(right),那取哪个呢,哪边多一个就取哪边 我们可以将j = (m + n) / 2 - i改为j = (m + n + 1) / 2 - i来保证j的值大些,从而保证len(left) > left(right) 也可以将j = (m + n) / 2 - i改为j = (m + n - 1) / 2 - i来保证j的值小些,从而保证len(right) > left(left) 最后就是一些特殊情况了: 首先由于j是由i决定的,j = (m + n) / 2 - i, i的取值范围是0到m,也就是说j可能的值是(n - m) / 2 到(m + n) / 2,由于j不能为负,那么反推m <= n
特殊处理: 如果i == 0或者i == m时,nums1数组有一边是没有值的 同理j == 0或者j == n时,nums2数组有一边也是没有值的 */ class Solution { public double findMedianSortedArrays(int[] nums1, int[] nums2) { if (nums1 == null && nums2 == null) { throw new IllegalArgumentException("nums1 and nums2 is null"); } int m = nums1.length; int n = nums2.length; // 保证 m <= n if (m > n) { int[] temp = nums1; nums1 = nums2; nums2 = temp; int tmp = m; m = n; n = tmp; } int iMin = 0, iMax = m; //保证len(left) > len(right) int halfLen = (m + n + 1) / 2; while (iMin <= iMax) { int i = (iMin + iMax) >>> 1; int j = halfLen - i; // i的值太大,这里注意i的值不断减小有可能i变为0,j变为n,必须保证大于0,j也必须小于n if (i > iMin && nums2[j] < nums1[i - 1]) { iMax = i - 1; } else if (i < iMax && nums1[i] < nums2[j - 1]) { // i 的值太小 iMin = i + 1; } else { // i的值刚好 int maxLeft = 0; // 特殊情况i == 0,数组nums1的left为空,只能取nums2的left的最大值 if (i == 0) { maxLeft = nums2[j - 1]; } else if (j == 0) { maxLeft = nums1[i - 1]; } else { maxLeft = Math.max(nums1[i - 1], nums2[j - 1]); } if ((m + n) % 2 == 1) { return maxLeft; }
int minRight = 0; if (i == m) { minRight = nums2[j]; } else if (j == n) { minRight = nums1[i]; } else { minRight = Math.min(nums2[j], nums1[i]); }
return (maxLeft + minRight) / 2.0; } } return 0.0; } }
|
如果您觉得文章有用或对您有帮助,欢迎通过以下方式赞助我。 ♪(^∀^●)ノ