设计一个O(n2)时间的算法,找出由n个数组成的序列的最长单调递增子序列。

时间:2021-01-14 09:52:19

题目如下:

设计一个O(n2)时间的算法,找出由n个数组成的序列的最长单调递增子序列。

解题思路:

思路一:简单dp,求最长递增子序列,即为求其与已经排好序的序列的公共子序列


/*设计一个O(n2)时间的算法,找出由n个数组成的序列的最长单调递增子序列。*/
#include <iostream>
#include<vector>
#include<algorithm>
using namespace std;
#define N 100

void fun(int n);

vector< int > a,b;

void main()
{
	int i,n,temp;
	printf("input n:");
	scanf("%d",&n);
	printf("input the array.\n");
	for(i=0;i<n&&cin>>temp;i++)
		a.push_back(temp);
	b=a;
	sort(b.begin(),b.end());
	fun(n);

}

void fun(int n)
{
	int m[N][N],flag[N];
	if(a[0]!=b[0])
		m[0][0]=0;
	else
		m[0][0]=1;
	for(int i=0;i<n;i++)
	{
		for(int j=0;j<n;j++)
		{
			if(i==0&&j==0)
			{
				continue;
			}
			if(a[i]==b[j])
			{
				if(i==0)
					m[i][j]=m[0][j-1]+1;
				else if(j==0)
					m[i][j]=m[i-1][0]+1;
				else
				    m[i][j]=m[i-1][j-1]+1;
			}
			else
			{
				if(i==0)
					m[i][j]=m[i][j-1];
				else if(j==0)
					m[i][j]=m[i-1][j];
				else
					m[i][j]=(m[i-1][j]>m[i][j-1]?m[i-1][j]:m[i][j-1]);
			}
		}
	}
	for(int k=n-1;k>=0;k--)
	{
		if(k==0&&m[0][0]!=0)
			flag[k]=1;
		else if(m[k][k]>m[k-1][k-1])
			flag[k]=1;
		else
			flag[k]=0;
	}
	cout<<"len="<<m[n-1][n-1]<<endl;
	cout<<"the number are:";
	for(int h=0;h<n;h++)
	{
		if(flag[h])
		{
			cout<<a[h]<<" ";
		}
	}
	cout<<endl;
		
}


第二种思路

/*设计一个O(n2)时间的算法,找出由n个数组成的序列的最长单调递增子序列。*/
#include <stdio.h>
#define N 100

void prin(int i);
void fun(int n);
int p[N],a[N];

void main()
{
	int i,n;
	printf("input n:");
	scanf("%d",&n);
	printf("input the array.\n");
	for(i=0;i<n;i++)
		scanf("%d",&a[i]);
	fun(n);

}

void fun(int n)
{
	int m[N];
	int i,k,max;
	m[0]=1;
	p[0]=-1;
	for(i=1;i<n;i++)
	{
		max=0;
		p[i]=-1;
		for(k=0;k<i;k++)
		{
			if(m[k]>max&&a[k]<a[i])
			{
				p[i]=k;
				max=m[k];                   
			}
		}
		m[i]=max+1;
	}
	i=0;
	for(k=1;k<n;k++)
	{
		if(m[k]>m[i])
		{
			i=k;
		}
	}	
	prin(i);
	printf("\nlen=%d\n",m[i]);

}

void prin(int i)
{
	if(p[i]<0)
	{
		printf("%d",a[i]);
		return;
	}
	prin(p[i]);
	printf(",%d",a[i]);
}