日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

有序数组求中位数问题

發布時間:2024/7/19 编程问答 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 有序数组求中位数问题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
1、有兩個已排好序的數組A和B,長度均為n,找出這兩個數組合并后的中間元素,要求時間代價為O(logn)。
2、假設兩個有序數組長度不等,同樣的求出中位數。
一:解析: 這個題目看起來非常簡單。第一題的話: 假設數組長度為n, 那么我就把數組1和數組2直接合并,然后再直接找到中間元素。對于這樣的方案,第一題和第二題就沒有什么區別了。這樣的話時間復雜度就是O(n)。通常在這樣的情況下,那些要求比較高的面試官就會循循善誘道:“你還有更好的辦法嗎?” 如果比線性更高效,直接能想到的就是對數了O(log(n)),這個時間復雜度在這里可能嗎? 當然還是可能的。
算法導論上面的分析是這樣的:
Say the two arrays are sorted and increasing, namely A and B.
It is easy to find the median of each array in O(1) time.
Assume the median of array A is m and the median of array B is n. Then,
1、If m==n,then clearly the median after merging is also m,the algorithm holds.
2、If m<=n,then reserve the half of sequence A in which all numbers are greater than m,also reserve the half of sequence B in which all numbers are smaller than n.
Run the algorithm on the two new arrays。
3、If m>n,then reserve the half of sequence A in which all numbers are smaller than m,also reserve the half of sequence B in which all numbers are larger than n.
Run the algorithm on the two new arrays。
Time complexity: O(logn)
下面,我們來畫個圖,分析一下這個思路:

我們先來分析看看: 想到對數的效率,首先想到的就是二分查找,對于這個題目二分查找的意義在哪里呢?
我們找到了A[n/2] 和 B[n/2]來比較,
1、如果他們相等,那樣的話,我們的搜索結束了,因為答案已經找到了A[n/2]就肯定是排序后的中位數了。
2、如果我們發現B[n/2] > A[n/2],說明什么,這個數字應該在 A[n/2]->A[n]這個序列里面, 或者在 B[1]-B[n/4]這里面。 或者,這里的或者是很重要的, 我們可以說,我們已經成功的把問題變成了在排序完成的數組A[n/2]-A[n]和B[0]-B[n/2]里面找到合并以后的中位數, 顯然遞歸是個不錯的選擇了。
3、如果B[n/2] < A[n/2]呢?顯然就是在A[0]-A[n/2]和B[n/2]-B[n]里面尋找了。

在繼續想, 這個遞歸什么時候收斂呢?當然一個case就是相等的值出現, 如果不出現等到這個n==1的時候也就結束了。
照著這樣的思路, 我們比較容易寫出如下的代碼, 當然邊界的值需要自己思量一下(遞歸代碼如下):
// 兩個長度相等的有序數組尋找中位數 int Find_Media_Equal_Length(int a[] , int b[] , int length) {if(length == 1){return a[0] > b[0] ? b[0] : a[0];}int mid = (length-1)/2;?? //奇數就取中間的,偶數則去坐標小的if(a[mid] == b[mid])return a[mid];else if(a[mid] < b[mid]){return Find_Media_Equal_Length(&a[length-mid-1] , &b[0] , mid+1);??? //偶數則取剩下的length/2,奇數則取剩下的length/2+1//return Find_Media_Equal_Length(a+length-mid-1 , b , mid+1);}else{return Find_Media_Equal_Length(&a[0] , &b[length-mid-1] , mid+1);//return Find_Media_Equal_Length(a , b+length-mid-1 , mid+1);} } 非遞歸代碼如下:
// 非遞歸代碼 int Find_Media_Equal_Length(int a[] , int b[] , int length) {int mid;while(1){if(length == 1){return a[0] > b[0] ? b[0] : a[0];}mid = (length-1)/2;if(a[mid] == b[mid])return a[mid];else if(a[mid] < b[mid])a = a + length - mid - 1; // a數組的后半部分elseb = b + length - mid - 1; // b數組的后半部分length = mid + 1;} } 二:馬上有人說那不定長的怎么辦呢?一樣的,我們還是來畫個圖看看:

一樣的, 我們還是把這個兩個數組來比較一下,不失一般性,我們假定B數組比A數組長一點。A的長度為n, B的長度為m。比較A[n/2]和B[m/2] 時候。類似的,我們還是分成幾種情況來討論:
a、如果A[n/2] == B[m/2],那么很顯然,我們的討論結束了。A[n/2]就已經是中位數,這個和他們各自的長度是奇數或者偶數無關。
b、如果A[n/2]? <?? B[m/2],那么,我們可以知道這個中位數肯定不在[A[0]---A[n/2])這個區間內,同時也不在[B[m/2]---B[m]]這個區間里面。這個時候,我們不能沖動地把[A[0]---A[n/2])和[B[m/2]---B[m]]全部扔掉。我們只需要把[B[m-n/2]---B[m]]和[A[0]---A[n/2])扔掉就可以了。(如圖所示的紅色線框),這樣我們就把我們的問題成功轉換成了如何在A[n/2]->A[n]這個長度為 n/2 的數組和 B[1]-B[m-n/2]這個長度為m-n/2的數組里面找中位數了,問題復雜度即可下降了。
c、只剩下A[n/2] > B[m/2],和b類似的,我們可以把A[n/2]->A[n]這塊以及B[1]->B[n/2]這塊扔掉了就行,然后繼續遞歸。
我們也可以寫出如下的代碼:
// 兩個長度不相等的有序數組尋找中位數 int Find_Media_Random_Length(int a[] , int lengtha , int b[] , int lengthb) {int mida = lengtha/2;int midb = lengthb/2;int l = (mida <= midb) ? mida : midb;if(lengtha == 1){if(lengthb % 2 == 0){if(a[0] >= b[midb])return b[midb];else if(a[0] <= b[midb-1])return b[midb-1];return a[0];}elsereturn b[midb];}else if(lengthb == 1){if(lengtha % 2 == 0){if(b[0] >= a[mida])return a[mida];else if(b[0] <= a[mida-1])return a[mida-1];return b[0];}elsereturn a[mida];}if(a[mida] == b[midb])return a[mida];else if(a[mida] < b[midb])return Find_Media_Random_Length(&a[mida] , lengtha-l , &b[0] , lengthb-l);elsereturn Find_Media_Random_Length(&a[0] , lengtha-l , &b[midb] , lengthb-l); } 舉例如下:
A:1、2、8、9、10
B:1、2、3、4、11
第一次:
A:1、2、{8}、9、10
B:1、2、{3}、4、11
因為8>3,所以第二次:
A:1、{2}、8
B:3、{4}、11
因為2<4,所以第三次:
A:{2}、8
B:{3}、4
因為2<3,所以第四次:
A:{8}
B:{3}

再舉一個簡單的例子:
A: 1 3 5 7 9
B: 2 4 6 8 10
結果我們都知道是5(下中位數)。
第一步:取5 和 6比較,發現5<6,則在 7 9 2 4中尋找嗎?
偶數的情況類似:
A: 1 3 5 7 9 11
B: 2 4 6 8 10 12
第一步:取5 和 6比較,發現5<6,則在 7 9 11 2 4中尋找嗎?
個人認為取一半的時候一定需要包含用于比較的兩個中位數(無論奇偶)。
就是說上面的兩個例子第一步之后:
在A:5 7 9??? B:2 4 6中繼續找
在A:5 7 9 11??? B:2 4 6中繼續找
但這樣導致新的問題是:新的數組A和B數字個數不一致了!
辦法是: 在遞歸的過程中,當數組中的元素是偶數時,在一個數組中取上中位數,在另一個數組中取下中位數,并且在整個過程中保持不變。在哪個數組中去上中位數,就一直在那個數組中取上中位數,反之亦然。奇數時的情形依舊。
這也就解釋了為什么代碼中a[mid]<b[mid] 的時候,a數組的開始位置會是: a[length-mid-1]

總結

以上是生活随笔為你收集整理的有序数组求中位数问题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。