[作业系列]算法第二章上机实践报告

1.实践题目:

两个有序序列的中位数 

2.问题描述:

已知有两个等长的非降序序列S1, S2, 设计函数求S1与S2并集的中位数。有序序列A0​​,A1​​,,AN1​​的中位数指A(N1)/2​​的值,即第(N+1)/2⌋个数(A0​​为第1个数)。

输入格式:

输入分三行。第一行给出序列的公共长度N(0<N≤100000),随后每行输入一个序列的信息,即N个非降序排列的整数。数字用空格间隔。

输出格式:

在一行中输出两个输入序列的并集序列的中位数。

3.算法描述:

#include<iostream>
using namespace std;
const int maxn = 2e5+5;
int a[maxn];
int n,x,cnt=1; 
int main()
{
    		cin>>n;
    for(int i=1;i<=2*n;i++)
            cin>>a[i];
            int cnt1=1,cnt2=n+1;
    for(;cnt<n+1;cnt++){
     	if  (a[cnt1]<a[cnt2])     	x=a[cnt1++];
     	else                     	x=a[cnt2++];
    }
            cout<<x<<endl;
}

  

开两个数组存两个序列,然后用两个指针从头按大小一路扫过去并用,cnt和x记录新序列的位置和值,由于没有去重,那么新序列的中位数就是指针扫到n时的值。

4.算法时间及空间复杂度分析:

由于是线性的直接遍历一遍,所以时间复杂度是O(N)的;

空间复杂度上,我开了1个2e5+5的数组,所以空间复杂度是O(2e5);

5.心得体会

这题虽然说是并集但其实不用去重,去重的话你最后一个样例是过不了的,因为这个原因我debug了大半小时。

其实这题还有一个log的算法,大概的思路是先在两个序列里找到N/2的子序列,判断子序列的最大值(由于是有序的,这个可以O(1)达到)把小的那个序列扔出去,并且维护扔出去的元素的最大值,然后在从小到大找到max(N/4,1)的子序列,再一次把小的那个子序列扔出去,维护扔出去的元素的最大值(包含之前扔出去的元素),继续对接下来的序列进行同样的操作(长度变为max(N/8,1)).......直至扔出的序列长度达到N,此时扔出去的最大值就是所要求的中位数,这个时间复杂度度是log级别的,因为每次都进行了二分的操作(寻找子序列的位置的时候由于是有序的所以是O(1)的),这个由于一开始没想出来所以我也没有敲代码,不过思路上来讲挺好实现的。

想了一下还是补充一下log的代码吧(没有特意出测试来调,但应该没错)

#include<bits/stdc++.h>
using namespace std;
const int maxn =1e5+5;
int a[maxn];
int b[maxn]; 
int main()
{
	int n,mid1=0,mid2=0;
	cin>>n;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	for(int i=1;i<=n;i++)
	cin>>b[i];
	int r1=n,r2=n,l1=0,l2=0,len=n,_max=0,l=0;
	while(l!=n)
	{
		len=max(len/2,1);
		mid1=l1+len;
		mid2=l2+len;
	//	cout<<len<<" "<<mid1<<" "<<mid2<<endl;
		if(a[mid1]<b[mid2])
		{
			_max=max(_max,a[mid1]);
			l1=mid1;
	//		cout<<_max<<"   A"<<endl;
		}
		else
		{
			_max=max(_max,b[mid2]);
			l2=mid2;
	//		cout<<_max<<"   B"<<endl;
		}
		l+=len;
	}
	cout<<_max<<endl;
}

  

 

posted @ 2018-10-13 21:08  咸鱼洲斩咸鱼风  阅读(250)  评论(0编辑  收藏  举报