#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;
}