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)).有兩個有序數組nums1和nums2,他們的大小各是m和n,請找出這兩個數組全部數的中位數,總得時間複雜度不超過O(log(m+n))java
時間O(n) 空間O(1)數組
若是對時間複雜度沒有要求,這個方法是實現起來最簡單的,咱們只須要從下往上依次數(n+m)/2個元素便可。因爲兩個數組都已經排序,咱們可使用兩個指針指向數組「底部」,經過比較兩個數組「底部」的元素大小來決定計哪個元素,同時將其所在數組的指針「向上」移一位。爲了方便處理總元素爲偶數的狀況,這裏將找中位數變成找第k小的元素。ide
public class Solution { public double findMedianSortedArrays(int[] nums1, int[] nums2) { int len1 = nums1.length; int len2 = nums2.length; int total = len1 + len2; if(total % 2==0){ return (findKth(nums1,nums2,total/2)+findKth(nums1,nums2,total/2+1))/2.0; } else { return findKth(nums1,nums2,total/2+1); } } private int findKth(int[] nums1, int[] nums2, int k){ int p = 0, q = 0; for(int i = 0; i < k - 1; i++){ if(p>=nums1.length && q<nums2.length){ q++; } else if(q>=nums2.length && p<nums1.length){ p++; } else if(nums1[p]>nums2[q]){ q++; } else { p++; } } if(p>=nums1.length) { return nums2[q]; } else if(q>=nums2.length) { return nums1[p]; } else { return Math.min(nums1[p],nums2[q]); } } }
時間O(log(m+n)) 空間O(1)指針
題目要求O(log(m+n))的時間複雜度,通常來講都是分治法或者二分搜索。首先咱們先分析下題目,假設兩個有序序列共有n個元素(根據中位數的定義咱們要分兩種狀況考慮),當n爲奇數時,搜尋第(n/2+1)個元素,當n爲偶數時,搜尋第(n/2+1)和第(n/2)個元素,而後取他們的均值。進一步的,咱們能夠把這題抽象爲「搜索兩個有序序列的第k個元素」。若是咱們解決了這個k元素問題,那中位數不過是k的取值不一樣罷了。code
那如何搜索兩個有序序列中第k個元素呢,這裏又有個技巧。假設序列都是從小到大排列,對於第一個序列中前p個元素和第二個序列中前q個元素,咱們想要的最終結果是:p+q等於k-1,且一序列第p個元素和二序列第q個元素都小於總序列第k個元素。由於總序列中,必然有k-1個元素小於等於第k個元素。這樣第p+1個元素或者第q+1個元素就是咱們要找的第k個元素。排序
因此,咱們能夠經過二分法將問題規模縮小,假設p=k/2-1,則q=k-p-1,且p+q=k-1。若是第一個序列第p個元素小於第二個序列第q個元素,咱們不肯定二序列第q個元素是大了仍是小了,但一序列的前p個元素確定都小於目標,因此咱們將第一個序列前p個元素所有拋棄,造成一個較短的新序列。而後,用新序列替代原先的第一個序列,再找其中的第k-p個元素(由於咱們已經排除了p個元素,k須要更新爲k-p),依次遞歸。同理,若是第一個序列第p個元素大於第二個序列第q個元素,咱們則拋棄第二個序列的前q個元素。遞歸的終止條件有以下幾種:遞歸
public class Solution { public double findMedianSortedArrays(int[] nums1, int[] nums2) { int m = nums1.length, n = nums2.length; int k = (m + n) / 2; if((m+n)%2==0){ return (findKth(nums1,nums2,0,0,m,n,k)+findKth(nums1,nums2,0,0,m,n,k+1))/2; } else { return findKth(nums1,nums2,0,0,m,n,k+1); } } private double findKth(int[] arr1, int[] arr2, int start1, int start2, int len1, int len2, int k){ // 保證arr1是較短的數組 if(len1>len2){ return findKth(arr2,arr1,start2,start1,len2,len1,k); } if(len1==0){ return arr2[start2 + k - 1]; } if(k==1){ return Math.min(arr1[start1],arr2[start2]); } int p1 = Math.min(k/2,len1) ; int p2 = k - p1; if(arr1[start1 + p1-1]<arr2[start2 + p2-1]){ return findKth(arr1,arr2,start1 + p1,start2,len1-p1,len2,k-p1); } else if(arr1[start1 + p1-1]>arr2[start2 + p2-1]){ return findKth(arr1,arr2,start1,start2 + p2,len1,len2-p2,k-p2); } else { return arr1[start1 + p1-1]; } } }