算法描述
給定兩個大小爲 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 ] ;
}