Leetcode4 Median of Two Sorted Arrays
這是一道Hard的題,確實是難誒,感覺就是道數學題,像高考數學求導的那道大題一樣,各種情況和邊界條件需要考慮,還需要推導。自己沒寫出來,
主要參考Solution: https://leetcode.com/problems/median-of-two-sorted-arrays 和discuss:https://leetcode.com/problems/median-of-two-sorted-arrays/discuss/2481/Share-my-O(log(min(mn))-solution-with-explanation
他們的思路是一樣的,不過一個是java一個是python而已。
詳細的可以去看原文,這裡只整理思路。
首先是根據中位數的定義,將問題等價為了
left_part | right_part
A[0], A[1], ..., A[i-1] | A[i], A[i+1], ..., A[m-1] B[0], B[1], ..., B[j-1] | B[j], B[j+1], ..., B[n-1]
用i,j去分割AB兩個陣列,如果上面的分割可以得到中位數,那麼有
1) len(left_part) == len(right_part) or
len(right_part)+1 (人為規定如果odd的話leftpart大一點,這個無所謂,leftpart大的話就從leftpart找結果就行)
2) max(left_part) <= min(right_part)
那麼even: median = (max(left_part) + min(right_part))/2 ;odd: median=left_part[-1]
上面兩條件等價:
1) i+j = m-i+n-j or m-i+n-j+1
2) A[i-1]<=B[j] and B[j-1]<=A[i]
其中對於1)我們可以約束m<=n,那麼有 j = (m+n+1)//2-i 。於是:
1) j = (m+n+1)//2-i s.t.m<=n
2) A[i-1]<=B[j] and B[j-1]<=A[i]
在條件1)下,有了i我們就有了j,於是我們在[0,m]裡對i進行二分查詢。(為什麼是左閉右閉呢,因為i其實是一個位置,而不是一個元素,比如i=0,代表在元素0之前分割,i=m,代表在元素m之前(元素m不存在,等價與元素m-1之後分割))
對於2)i=0時,A[i-1]不存在;類似的,j=0,i=m,j=n時,B[j-1],A[i],B[j]不存在,所以這個邊界條件我們也要處理一下。
i=0時,說明我們對i的搜尋已經進行完畢,A組資料都應該在rightpart,那麼i就是我們要的i了,至於結果怎麼樣要看是odd還是even了;
i=m時,A組資料都應該在leftpart,那麼i就是我們要的i了;
j類似。
所以,i什麼時候小呢?
B[j-1]>A[i]&&j!=0&&i!=m
等價於 B[j-1]>A[i]&&j>0&&i<m
i什麼時候大呢?
A[i-1]>B[j]&&i!=0&&j!=n
等價於 A[i-1]>B[j]&&i>0&&j<n
剩下的時候就是i合適了。
但是這時i=0,j=0,i=m,j=n這幾個特殊情況會影響我們的公式,所以要特殊處理。
照這個思路寫了一版,並不對,先放這兒吧。
class Solution { public double findMedianSortedArrays(int[] nums1, int[] nums2) { int m=nums1.length,n=nums2.length; //ensure m<=n orelse j=(m+n+1)/2-i might be a negative interger ,that's not what we want if(m>n) { int[] temp=nums1;nums1=nums2;nums2=temp; int tempi = m;m=n;n=tempi; } if(m==0) { if(n%2==0) return (nums2[n/2-1]+nums2[n/2])/2.0; else return (double)nums2[n/2]; } //i,j represents where we divide nums1,nums2 to two equivalent parts or len(left)==len(right)+1 int i=0,j=(m+n+1)/2-i; //binary search int pl=0,pr=m; while(pl<=pr) { i=(pl+pr)/2; j=(m+n+1)/2-i; int leftmax,rightmin; if(j>0&&i<m&&nums2[j-1]>nums1[i]) { //i is too small pl=(pl+pr)/2+1; } else if(i>0&&j<n&&nums1[i-1]>nums2[j]) { //i is too big pr=(pl+pr)/2-1; } else { //i,j are what we want if(i==0) leftmax=nums2[j-1]; else if(j==0) leftmax=nums1[i-1]; else leftmax=Math.max(nums1[i-1],nums2[j-1]); if(i==m) rightmin=nums2[j]; else if(j==n) rightmin=nums1[i]; else rightmin = Math.max(nums1[i], nums2[j]); if((m+n)%2==0) return (leftmax+rightmin)/2.0; else return (double)leftmax; } } return 0.0; } }Wrong Answer Input [1,2]
[-1,3] Output 2.0 Expected 1.5