描述
There are two sorted arrays nums1 and nums2 of size m and n respectively.
Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
You may assume nums1 and nums2 cannot be both empty.
Example 1:
nums1 = [1, 3]
nums2 = [2]
The median is 2.0Example 2:
nums1 = [1, 2]
nums2 = [3, 4]
The median is (2 + 3)/2 = 2.5思路
题目明确指出时间复杂度应该在O(log (m+n))。猜测可能用到树型数据结构进行优化。自己没思路。
先试一下不限制时间复杂度的:合并两个数组,再取合并完成的数组(有序)的中位数。
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int totalLen = nums1.length + nums2.length;
int[] total = new int[totalLen];
int i1 = 0, i2 = 0, count = 0;
while(i1<nums1.length && i2<nums2.length){
if(nums1[i1]<nums2[i2]){
total[count] = nums1[i1];
i1++;
}else{
total[count] = nums2[i2];
i2++;
}
count++;
}
while(i1<nums1.length){
total[count] = nums1[i1];
i1++;count++;
}
while(i2<nums2.length){
total[count] = nums2[i2];
i2++;count++;
}
if(totalLen%2 == 0){
return (double)(total[totalLen/2 -1] + total[totalLen/2])/2;
}else{
return (double)total[(totalLen-1)/2];
}
}
}时间复杂度应该是O(m+n),大于题目要求。不过居然也AC了。时间空间消耗看起来也都不错。
变换思路
看了评论区的解,没有用到树型数据结构,使用到了二分法。非常巧妙。
In order to solve this question, we need to first understand what a median is. A median is the middle value of a dataset.
Since we have 2 seperately sorted array in this question, to find the middle value is somewhat complicated. However, keep in mind that we do not care about the actual value of the numbers, what we want is the middle point from the combination of 2 arrays. In other words, we are looking for the middle index of the 2 arrays. Thus approach likebinary searchcould be employed.
Based on the fact that the 2 arrays are sorted seperatedly, we could try to get the submedian of the 2 arrays in each round. Than compare them. And the basic idea is that the left half of the array with a smaller submedian can never contains the common median.
该思想的方法是,在原数组保证有序的情况下,通过不断的调整两个整型数组的两个分隔指针(一个数组一个)。使得第一个数组指针左边的元素全部小于第二个数组指针右边的元素,使第二个数组指针左边的元素全部小于第一个数组指针右边的元素。
由于数组本身是有序的,如此一来只要使得两个指针左边的数字数量和指针右边的数字数量相等,就可以得到所有元素的中位数(一个或者是两个的平均值,即左边两个数组的最大数字和右边两个数组的最小值)。
进行上述调和过程的时候对移动步长使用二分法控制指针移动的位置。
public class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
// Deal with invalid corner case.
if (nums1 == null || nums2 == null || nums1.length == 0
|| nums2.length == 0) return 0.0;
int m = nums1.length, n = nums2.length;
int l = (m + n + 1) / 2; //left half of the combined median
int r = (m + n + 2) / 2; //right half of the combined median
// If the nums1.length + nums2.length is odd,
// the 2 function will return the same number
// Else if nums1.length + nums2.length is even,
// the 2 function will return the left number and right number that make up a median
return (getKth(nums1, 0, nums2, 0, l) + getKth(nums1, 0, nums2, 0, r)) / 2.0;
}
private double getKth(int[] nums1, int start1, int[] nums2, int start2, int k) {
// This function finds the Kth element in nums1 + nums2
// If nums1 is exhausted, return kth number in nums2
if (start1 > nums1.length - 1) return nums2[start2 + k - 1];
// If nums2 is exhausted, return kth number in nums1
if (start2 > nums2.length - 1) return nums1[start1 + k - 1];
// If k == 1, return the first number
// Since nums1 and nums2 is sorted,
// the smaller one among the start point of nums1 and nums2 is the first one
if (k == 1) return Math.min(nums1[start1], nums2[start2]);
int mid1 = Integer.MAX_VALUE;
int mid2 = Integer.MAX_VALUE;
if (start1 + k / 2 - 1 < nums1.length) mid1 = nums1[start1 + k / 2 - 1];
if (start2 + k / 2 - 1 < nums2.length) mid2 = nums2[start2 + k / 2 - 1];
// Throw away half of the array from nums1 or nums2. And cut k in half
if (mid1 < mid2) {
// nums1.right + nums2
return getKth(nums1, start1 + k / 2, nums2, start2, k - k / 2);
} else {
// nums1 + nums2.right
return getKth(nums1, start1, nums2, start2 + k / 2, k - k / 2);
}
}
}时间空间消耗差不多,但这种方法的时间复杂度是符合题意的。