算法描述
给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
示例 1:
nums1 = [1, 3]
nums2 = [2]
则中位数是 2.0
示例 2:
nums1 = [1, 2]
nums2 = [3, 4]
则中位数是 (2 + 3)/2 = 2.5
第一个版本
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
// 每次去掉一个最小,一个最大,需要四个下标
if (null == nums1 || nums1.length == 0) {
return getNum(nums2);
}
if (null == nums2 || nums2.length ==0){
return getNum(nums1);
}
int[] nums = new int[nums1.length + nums2.length];
// 都不为空
int indx1 = 0;
int indx2 = 0;
int idx = 0;
// 当全部都还没取完
while(indx1 != nums1.length && indx2 != nums2.length){
if (nums1[indx1] > nums2[indx2]){
// 放小的
nums[idx++] = (nums2[indx2++]);
}else{
nums[idx++] = (nums1[indx1++]);
}
}
if (indx1 != nums1.length){
//TODO
for(int i = indx1; i < nums1.length; i++){
nums[idx++] = nums1[i];
}
}
if (indx2 != nums2.length){
for(int i = indx2; i < nums2.length; i++){
nums[idx++] = nums2[i];
}
}
for (int i = 0; i < idx; i++){
System.out.println(nums[i]);
}
return getNum(nums);
}
private double getNum(int[] num){
return ((num.length) & 1) == 0 ? (double)((num[(num.length >> 1) - 1] + num[num.length >> 1])/2.0) : num[num.length >> 1 ] ;
}
这个版本浪费了很多空间,可以将空间复杂度降到O(1),也就是优化后的版本。
优化版本
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
// 每次去掉一个最小,一个最大,需要四个下标
if (null == nums1 || nums1.length == 0) {
return getNum(nums2);
}
if (null == nums2 || nums2.length ==0){
return getNum(nums1);
}
// 找下标
int totalLen = nums1.length + nums2.length;
boolean isOdd = (totalLen & 1) > 0;
int theFisrtPosition = ((totalLen + 1) >> 1 ) - 1; // 假设已经排序,这是
// 都不为空
int indx1 = 0;
int indx2 = 0;
int startIndex = -1; // 指向上一个虚拟数组中的下标
// 当全部都还没取完
int tmp = 0;
while(indx1 < nums1.length && indx2 < nums2.length && startIndex < theFisrtPosition){
if (nums1[indx1] > nums2[indx2]){
tmp = nums2[indx2++];
}else{
tmp = nums1[indx1++];
}
startIndex++;
}
// 计数到thefirstIdx,或者存在一个数组用完,找到接下来的两个
if(startIndex == theFisrtPosition){ // 计数到theFirstIdx
if (isOdd){ // 奇数
return tmp;
}else{
return (tmp + Math.min(indx1== nums1.length ? Integer.MAX_VALUE : nums1[indx1],
indx2 == nums2.length ? Integer.MAX_VALUE : nums2[indx2]))/2.0;
}
// 直接就可以return了,找到接下来两个该放的数值
}else{ // 没有数到,有用完的了
if(indx1 == nums1.length){ // 在nums2里面
return isOdd ? nums2[indx2 + (theFisrtPosition - startIndex - 1)] :
(nums2[indx2 + (theFisrtPosition - startIndex - 1)]
+ nums2[indx2 + (theFisrtPosition - startIndex)])/2.0;// 是奇数,在再另外一个里面计算
}else{
return isOdd ? nums1[indx1 + (theFisrtPosition - startIndex - 1)] :
(nums1[indx1 + (theFisrtPosition - startIndex - 1)]
+ nums1[indx1 + (theFisrtPosition - startIndex)])/2.0;// 是奇数,在再另外一个里面计算
}
}
}
private double getNum(int[] num){
return ((num.length) & 1) == 0 ? (double)((num[(num.length >> 1) - 1] + num[num.length >> 1])/2.0) : num[num.length >> 1 ] ;
}