1. 程式人生 > >[LeetCode] Median of Two Sorted Arrays

[LeetCode] Median of Two Sorted Arrays

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.0

Example 2:

nums1 = [1, 2]
nums2 = [3, 4]
The median is (2 + 3)/2 = 2.5

題意:給出兩個陣列,兩個陣列都是升序的,輸出這兩個陣列所有數的中位數,要求時間複雜度為O(log (m+n))

思路:這道題比較難了,時間複雜度要求比較高,如果沒有時間複雜度限制的話,我們可以把兩個數組合並,然後排序,這樣時間複雜度為O((m+n)log (m+n));也可以像歸併排序那樣合併兩個陣列,合併之後就為有序的了,時間複雜度為O(m+n)。但這樣與題目要求相比都會超時。要求中位數,如果(n+m)是奇數的話為最中間的那個數,如果為偶數的話為最中間那兩個數的平均值,我麼可以統一一下,無論是奇數還是偶數,我們都找第(n+m+1)/ 2個數與第(n+m+2)/ 2的平均值。

這樣問題就轉化為求兩個升序陣列第k個數的問題了,利用二分+分治的思想,我們二分k,分別在兩個陣列內找第k/2個數mid1,mid2,如果mid1<mid2.,就說明第k個數肯定不會在第一個陣列的前k/2個數內,所以排除這一部分,我們只需在第一個陣列的剩餘部分和整個第二個陣列內找第k-k/2個就可以了,這樣分治下去,為了避免產生新的陣列,這裡是用兩個變數i和j表示兩個陣列的起始位置,分治下去肯定要有終止條件,當其中一個數組不存在第k/2個數的時候,直接返回另一個數組的第k個數就行了;還有當k為1的時候,也不需在分治下去了,返回兩個陣列較小的一個值就行了。

C程式碼:

int findK(int *nums1,int nums1Size,int i,int* nums2,int nums2Size,int j,int k)
{  
    if(i >= nums1Size) return nums2[j + k - 1];
    if(j >= nums2Size) return nums1[i + k - 1];
    if(k == 1) return nums1[i] < nums2[j] ? nums1[i] : nums2[j];
    int mid1 = (i + k / 2 - 1) < nums1Size ? nums1[i + k / 2 - 1] : INT_MAX;
    int mid2 = (j + k / 2 - 1) < nums2Size ? nums2[j + k / 2 - 1] : INT_MAX;
    if(mid1 < mid2) {
        return findK(nums1,nums1Size,i + k / 2,nums2,nums2Size,j,k - k / 2);
    }
    else {
        return findK(nums1,nums1Size,i,nums2,nums2Size,j + k / 2,k - k / 2);
    }
}
double findMedianSortedArrays(int* nums1, int nums1Size, int* nums2, int nums2Size)
{
    return ( findK(nums1,nums1Size,0,nums2,nums2Size,0,(nums1Size + nums2Size + 1) / 2) +
    findK(nums1,nums1Size,0,nums2,nums2Size,0,(nums1Size + nums2Size + 2) / 2) ) / 2.0;
}

Java程式碼:

public class Solution {
	public int findK(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 nums1[i] <= nums2[j] ? nums1[i] : nums2[j];
		int mid1 = i + k / 2 - 1 < nums1.length ? nums1[i + k / 2 - 1] : Integer.MAX_VALUE;
		int mid2 = j + k / 2 - 1 < nums2.length ? nums2[j + k / 2 - 1] : Integer.MAX_VALUE;
		if(mid1 < mid2) {
			return findK(nums1,i + k / 2,nums2,j,k - k / 2);
		}
		else {
			return findK(nums1,i,nums2,j + k / 2,k - k / 2);
		}
	}
	public double findMedianSortedArrays(int[] nums1, int[] nums2) {	
		return ( findK(nums1,0,nums2,0, ( nums1.length + nums2.length + 1) / 2) + 
				findK(nums1,0,nums2,0, ( nums1.length + nums2.length + 2) / 2) )  / 2.0;
	}
}