算法:最长递增子序列、最长公共子串

#include<iostream>
#include<cstring>
#define MAXSEQUENCE 1000
#define MAXDIF 1000
using namespace std;
void Print_LCS(int (*rec)[100],int a[], int b[], int i, int j);


//---------最长递增子序列-----------

//动态规划 O(n*n)   递推式:len[i] = max{ len[k]+1 | a[k]< a[i] , 0<=k<i}
int LIS(int a[],int n)
{
	int len[MAXSEQUENCE];
	len[0]=1;
	
	for(int i=1;i<n;i++){
		len[i]=1;
		//此处是O(n),可用二分搜索来对此处改进 B数组,
		//下标是最大子序列长度,值是最小的最末元素,巧妙!!! (即下面的该函数LIS_bin)
		for(int j=0;j<i;j++)
			if(a[j]<a[i]&&len[j]+1>len[i])
				len[i]=len[j]+1;  
	}
	
	int maxlen=0;	
    for(int i=0;i<n;i++)
        if(len[i]>maxlen)
            maxlen=len[i];
		
	return maxlen;
}

//动态规划O(nlogn),求最长递增子串的长度更快捷,难以输出最长子串。
int LIS_bin(int a[],int n) 
{
	int B[MAXSEQUENCE];    
	int len=1;
	B[0]=a[0]; //注意此处的赋值,不是B[0]=0; 

	for(int i=1;i<n;i++){
		int left=0, right=len-1;
		while(left<=right){ //O(logn) 找到大于等于ai的第一个元素 ,返回时left指向 
			int m=(left+right)/2;
			if(B[m]<a[i]) left=m+1;
			else right=m-1;
		}

		B[left]=a[i];    //更新 
		if(left+1>len) len++;  //看是否长度要增大
	} 

	return len;
}

//o(n*n),但存储空间从o(n)增大到o(n*maxdis),maxdis为所有元素的最大差值,有没有更好的方法? 
int  LIS_EqualDif(int a[], int n) 
{  
	n=n;
	int len[MAXSEQUENCE][MAXDIF]; //当差增较大时,很快存储空间就不能定义了 
	//求最大差值
	int MaxVal=a[0], MinVal=a[0];
	for(int i=1;i<n;i++){
		if(MaxVal<a[i]) 
			MaxVal = a[i];
		else if(MinVal>a[i])
			MinVal = a[i];
	}                                       
	int MaxDif = MaxVal - MinVal;

	memset(len,0,n*(MaxDif+1)*sizeof(int));  
	for(int i=1;i<n;i++){
		for(int j=0;j<i;j++){
			int dis=a[i]-a[j];
			if(dis>=0) //注意是等差,所以相等也算 
				len[i][dis] = len[j][dis] + 1;
		}
	}

	int result=0;
	for(int i=0;i<n;i++)
		for(int j=0;j<=MaxDif;j++)
			if(result<len[i][j])
				result = len[i][j];

	return result+1;
}


//---------最长公共子序列-----------

//动态规划,O(mn) ,a.length=m, b.length=n 
int LCS(int a[], int n,int b[],int m)
{
	int len[MAXSEQUENCE][MAXSEQUENCE]; //从下标1开始,记录i,j之前的最大长度 

	for(int i=0;i<n;i++)
		len[i][0]=0;
	for(int i=0;i<m;i++)
		len[0][i]=0;

	int i,j;
	for(i=0;i<n;i++){
		for(j=0;j<m;j++){
			if(a[i]==b[j]){  //如果相等 
				len[i+1][j+1]=len[i][j]+1;
			}
			else{// 不相等 
				if( len[i][j+1]>len[i+1][j] )
					len[i+1][j+1]=len[i][j+1];
				else
					len[i+1][j+1]=len[i+1][j];
			}
					
		}
	}

	return len[i][j];
}


//分治,最长公共子串,O(2^n) ,有太多的重复计算,导致复杂度呈指数级增长 
int LCS_recur(int a[], int n, int b[],int m)
{
	if(m==0||n==0)
		return 0;
	if(a[n-1]==b[m-1]){
		return LCS_recur(a,n-1,b,m-1)+1;
	}
	else{
		int tmp1=LCS_recur(a,n-1,b,m);
		int tmp2=LCS_recur(a,n,b,m-1);
		if(tmp1>tmp2)
			return tmp1;
		else
			return tmp2;
	} 
}


int main()
{
loop: 

	int a[MAXSEQUENCE],b[MAXSEQUENCE],n,m;
	//LIS
	printf("n: ");
	scanf("%d",&n);
	for(int i=0;i<n;i++)
		scanf("%d",&a[i]);	
	printf("LIS: %d\n",LIS(a,n));
	printf("LIS_bin: %d\n",LIS_bin(a,n));
	printf("LIS_EqualDif: %d\n",LIS_EqualDif(a,n));

	//LCS
	printf("m: ");
	scanf("%d",&m);
	for(int i=0;i<m;i++)
		scanf("%d",&b[i]);
	printf("LCS: %d\n",LCS(a,n,b,m));
	printf("LCS_recur: %d\n",LCS_recur(a,n,b,m));

goto loop;     
	return 0;   
} 


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值