LeetCode 求中位數 最優解( 那不是座標雖然很像但是不是)
阿新 • • 發佈:2021-09-13
public double findMediandArrays(int[] A ,int[] B){ int m = A.length; int n = B.length; // 長度無所謂 但是必須知道 誰長誰短 這裡涉及取值範圍的問題 if(m>n){ // 尾遞迴不會棧堆積 findMediandArrays(B,A); } // I的取值範圍 最小為 0 最大值為 m int maxI = m,minI = 0; while(maxI>=minI){ // 這個i不是座標 是陣列A切割點的位置與實際座標有差異 一定要明確這點這也是困擾我很久的問題 // 這裡是將 陣列A 一分為二 取到了A的中位數 // 如果A為奇數 中位數為i 為偶數 中位數為 2分之 A[i]+A[i-1] // [1,2,3] [1,2,3,4] 有興趣自己代入一下 int i = (maxI+minI)/2; // 這裡是 陣列B的切割點 這個切割點和 i 相關也就是 通過i 求 j// 因為中位數的位置不變 永遠是(m+n)/2 所以求出了一個得知一個數組的切割位置就知道另一個的切割點 // 這也是之前為什麼要區分長短的原因 如果不區分長短 j 有可能為負數 // 為什麼加一呢是 奇偶合並 這裡的合併不是 偶數合併為奇數 // 而是奇數合併為偶數 也就是說總長度為偶數 // 中位數永遠左節點為 (m+n)/2 -1 右節點分為 (m+n)/2 // 如果為奇數返回 做節點 如果為偶數返回左右節點的均值 int j = (m+n+1)/2-i;// 移動切割點 這裡要先確認結果 再想條件 // 結果是 i 增加還是減小 if (i!=m&&j!=0 && A[i]<B[j-1]){ // i增加 j就會減小 j的最小值為0 i的最大值為 m // 所以 i增加要滿足 i!=m j!=0 // 然後理解什麼是中位數 // 因為陣列有序 所以 A[i]> A[i-1] // 因為陣列有序 所以 B[j]> B[j-1] // 如果 A[i]<B[j-1] 則需要增加i 減小 j 使其接近中位數條件 // 左邊最大值 小於右面最小值 // 所以 i要增大 minI = minI + 1; } //這裡是結果是i減小同理 else if (i!=0&&j!=n&&A[i-1]>B[j] ){ maxI = maxI - 1; }// 當切割點不再變更 則 找到中位數切割位置 開始求值 else { // 左邊最大值 int leftMax = 0; if (i == 0 ){ // 左邊最大值 i 和j 是切割點不是座標 leftMax = B[j-1]; }else if(j==0){ leftMax = A[i-1]; }else { leftMax = Math.max( B[j-1], A[i-1]); } //這個地方 不要用一個數組代入 想想中位數 因為 這個題解一切以中位數為基礎的理論 // 代入時要用兩個有序陣列 一個數組 無法代入 // 如果是奇數 直接返回左邊最大值就可以 if (((m+n)&1)==1){ return leftMax; } //右邊最小值 求職同理 int rightMin = 0; if (i == m ){ // 左邊最大值 i 和j 是切割點不是座標 rightMin = B[j]; }else if(j==n){ rightMin = A[i]; }else { rightMin = Math.min(B[j], A[i]); } return (leftMax+rightMin)/2.0; } } return 0.0; }