问题描述:两个有序数组,输出他们的中位数。The overall run time complexity should be O(log (m+n)).
Example 1:
nums1 = [1, 3] nums2 = [2] The median is 2.0
Example 2:
nums1 = [1, 2] nums2 = [3, 4] The median is (2 + 3)/2 = 2.5
solution1:因为时间复杂度要求O log(m+n), 想到用二分查找递归,因为对奇偶个数字中位数不同,采用一个trick:left=(m+n+1)/2, right=(m+n+2/2.对于奇数,两个相同,对于偶数,两者差一。但是有两个数组,每次对每个数组查找k/2。首先考虑边界问题:如果有一个数组不存在k/2的数(那么另一个必然存在),就把这个数组index置为Integer.MAX_VALUE,在另外一个数组找.如果k=1,就比较两个数组index第一个。对于一般情况,找到两个数组k/2之后,比较它们的大小,较小的index推进k/2,较大的不变,k减小k/2.
public class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length, n = nums2.length, left = (m + n + 1) / 2, right = (m + n + 2) / 2;
return (findKth(nums1, 0, nums2, 0, left) + findKth(nums1, 0, nums2, 0, right)) / 2.0;
}
int findKth(int[] nums1, int i, int[] nums2, int j, int k) {
if (i >= nums1.length) return nums2[j + k - 1];
if (j >= nums2.length) return nums1[i + k - 1];
if (k == 1) return Math.min(nums1[i], nums2[j]);
int midVal1 = (i + k / 2 - 1 < nums1.length) ? nums1[i + k / 2 - 1] : Integer.MAX_VALUE;
int midVal2 = (j + k / 2 - 1 < nums2.length) ? nums2[j + k / 2 - 1] : Integer.MAX_VALUE;
if (midVal1 < midVal2) {
return findKth(nums1, i + k / 2, nums2, j, k - k / 2);
} else {
return findKth(nums1, i, nums2, j + k / 2, k - k / 2);
}
}
}
solution 2:和第一种方法的区别是迭代中不断截短两个数组而不需要保留一个index。首先我们要判断数组是否为空,为空的话,直接在另一个数组找第K个即可。还有一种情况是当K = 1时,表示我们要找第一个元素,只要比较两个数组的第一个元素,返回较小的那个即可。这里我们分别取出两个数组的第K/2个数字的位置坐标i和j,为了避免数组没有第K/2个数组的情况,我们每次都和数组长度做比较,取出较小值。这里跟上面的解法有些许不同,上面解法我们直接取出的是值,而这里我们取出的是位置坐标,但是思想都是很类似的。不同在于,上面解法中我们每次固定淘汰K/2个数字,而这里我们由于取出了合法的i和j,所以我们每次淘汰i或j个。
public class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length, n = nums2.length, left = (m + n + 1) / 2, right = (m + n + 2) / 2;
return (findKth(nums1, nums2, left) + findKth(nums1, nums2, right)) / 2.0;
}
int findKth(int[] nums1, int[] nums2, int k) {
int m = nums1.length, n = nums2.length;
if (m == 0) return nums2[k - 1];
if (n == 0) return nums1[k - 1];
if (k == 1) return Math.min(nums1[0], nums2[0]);
int i = Math.min(m, k / 2), j = Math.min(n, k / 2);
if (nums1[i - 1] > nums2[j - 1]) {
return findKth(nums1, Arrays.copyOfRange(nums2, j, n), k - j);
} else {
return findKth(Arrays.copyOfRange(nums1, i, m), nums2, k - i);
}
}
}