算法第二章實踐報告
1. 實踐題目
7-3 兩個有序序列的中位數 (20 分)
已知有兩個等長的非降序序列S1, S2, 設計函數求S1與S2並集的中位數。有序序列A?0??,A?1??,?,A?N?1??的中位數指A?(N?1)/2??的值,即第?(N+1)/2?個數(A?0??為第1個數)。
2. 問題描述
即求兩個有序序列並集後的中位數,由於兩個有序序列並集的元素數2n量是偶數,因此即求這兩個序列並集後排序好的第n個元素。
3. 算法描述
#include<iostream>
using namespace std;
int main(void)
{
int n;
cin>>n;
int a[100001];
int b[100001];
for(int i=0;i<n;i++)
cin>>a[i];
for(int i=0;i<n;i++)
cin>>b[i];
int k=n-1;
int x=0,y=0;
while(1)
{
int md=k/2;
if(md!=0)
{
if(md%2==0)
{
if(a[x+md]==b[y+md])
{
cout<<a[x+md];
break;
}
else if(a[x+md]>b[y+md])
{
y+=md;
k-=md;
}
else
{
x+=md;
k-=md;
}
}
else
{
if(a[x+md]==b[y+md])
{
cout<<a[x+md];
break;
}
else if(a[x+md]>b[y+md])
{
y+=md+1;
k-=md+1;
}
else
{
x+=md+1;
k-=md+1;
}
}
}
else
{
if(k==0)
{
if(a[x]==b[y])
{
cout<<a[x];
break;
}
else if(a[x]>b[y])
{
cout<<b[y];
break;
}
else
{
cout<<a[x];
break;
}
}
if(k==1)
{
if(a[x]==b[y])
{
cout<<a[x];
break;
}
else if(a[x]>b[y])
{
y+=1;
k-=1;
}
else
{
x+=1;
k-=1;
}
}
}
}
return 0;
}
4. 算法時間及空間復雜度分析
求兩個數列並集後的有序的第n個元素,註意到第n個元素等價於前面有n-1個元素不大於它,符合這個條件的最小數即所求數。
我們先取兩個數組,各自元素為題給兩個數列的元素,計所求元素前面還有k個比它小的。
初始情況下k為n-1,取k/2,則先比較每個數組的第1+k/2個元素,如果a數組的第1+k/2個元素小於b數組的第1+k/2個元素,則a數組的前k/2個元素都可直接去掉,因為它們絕對不可能滿足有k個數比它們小。
然後我們已經去掉了k/2個數,重新得到數組a和數組b,並且此時k為k-k/2(註意不一定等於k/2),這樣問題就縮減為原來的一半規模了。直至k為0,此時比較a和b數組的首元素,誰小誰就是所求的中位數。
因此時間復雜度與二分搜索的一樣,每次都使問題規模縮減一半,即logn。
空間復雜度為o(n),即保存兩個數組元素的空間需求。
5. 心得體會(對本次實踐收獲及疑惑進行總結)
在做編程題目的時候,應該先把題目條件認真看完,例如題目中的中位數與我們以往學習的中位數概念有所偏差。
然後應該從題目條件開始入手,再結合算法思想完成題目。
在本次實踐中,對二分搜索算法有了進一步的認識以及基本上熟識了二分算法的思想。
算法第二章實踐報告