7-3 兩個有序序列的中位數 (20 分)
已知有兩個等長的非降序序列s1, s2, 設計函式求s1與s2並集的中位數。有序序列a0,a1,⋯,an−1的中位數指a(n−1)/2的值,即第⌊(n+1)/2⌋個數(a0為第1個數)。
輸入分三行。第一行給出序列的公共長度n(0≤100000),隨後每行輸入乙個序列的資訊,即n個非降序排列的整數。數字用空格間隔。
在一行中輸出兩個輸入序列的並集序列的中位數。
5
1 3 5 7 9
2 3 4 5 6
4
6
-100 -10 1 1 1 1
-50 0 2 3 4 5
1
給出兩個非降序序列,題目要求求出兩個序列並集的中位數。並集是指給定兩個集合a,b,把他們所有的元素合併在一起組成的集合。
然而這裡的並集是不去重的。
很容易的,最先想到的就是先把兩個序列合併,然後直接利用下標(a[n-1]+a[n])/2求得,這種方法的最優時間複雜度是利用歸併排序的o(n)達到。
但是,還有更快的方法,那就是直接利用序列式有序的這個前提,利用兩個序列的中位數查詢。
首先,很容易知道的。如果a[mid]>b[mid],那麼所求的中位數一定位於 b 序列的右邊與 a 序列的左邊;反之所求中位數一定在 a 序列的右邊與 b 序列的左邊。
利用這個想法,不斷分割序列,理論上,最後會剩下兩個數,這時 把兩個數相加除以二即為中位數。
但是還有乙個問題是,我們的想法是有漏洞的。
即我們的mid = (left+right)/2;
就拿樣例2來說,根據我們的演算法與求 mid 的式子:
-100
-10111
1-50
0234
5--111
1-50
02--
-過程中就有可能使兩個序列的長度不再相等,從而導致最終的結果出現錯誤。解決的方法就是在求 mid 的時候加一再除以二,從而保證兩條序列長度一直相等。
每次分別求中位數的時間複雜度為o(1)o(1
)'>,劃分區間的時間複雜度o(1
)'>o(1),根據計算得o(
1)'>o(1
)'>時間複雜度o(
logn
)'>o(logn)。o(
1)'>o(1
)'>o(l
ogn)
'>此演算法只需要常數個額外變數,空間複雜度為o(1
)'>o(1)。
#include #includeusing
namespace
std;
intn;
int a[1000005], b[1000005
];int solve(int a, int b, int aleft, int aright, int bleft, int
bright);
sort(num, num+4
);
int mid = (num[1] + num[2]) / 2
;
//cout << ans << endl;
//cout mid;
}//cout << "asfasdasda" << endl;
int amid = (aleft + aright+1) >> 1
;
int bmid = (bleft + bright) >> 1
;
if(a[amid] >b[bmid])
ans =solve(a, b, aleft, amid, bmid, bright);
else
ans =solve(a, b, amid, aright, bleft, bmid);
return
ans;
}int
main()
for(int i = 0; i < n ; i++)
int ans = solve(a, b, 0, n-1, 0, n-1
); cout
<< ans
}
多跟別人交流,很多時候思維黑洞會限制了發揮。
多動手模擬。
演算法第二章上機實踐報告
實踐題目名稱 找第k個小的數 問題描述 設計乙個平均時間為o n 的演算法,在n 1 n 1000 個無序的整數中找出第k小的數。演算法描述 就是先假設a left 為這個分界值x,然後排序。比較x是不是第k個如果是,返回這個值。如果不是比較一下x和a k 的大小,如果xa k 遞迴在x的右邊找 演...
演算法第二章上機實踐報告
7 1 最大子列和問題 20分 給定k個整數組成的序列,連續子列 被定義為,其中 1 i j k。最大子列和 則被定義為所有連續子列元素的和中最大者。例如給定序列,其連續子列有最大的和20。現要求你編寫程式,計算給定整數序列的最大子列和。本題旨在測試各種不同的演算法在各種資料情況下的表現。各組測試資...
演算法第二章上機實踐報告
1,實踐題目名稱 最大子列和問題 給定k個整數組成的序列,連續子列 被定義為,其中 1 i j k。最大子列和 則被定義為所有連續子列元素的和中最大者。例如給定序列,其連續子列有最大的和20。現要求你編寫程式,計算給定整數序列的最大子列和。本題旨在測試各種不同的演算法在各種資料情況下的表現。各組測試...