从给定序列中按原来的顺序取出若干元素组成的序列称为子序列,当取出全部元素时,子序列等于原序列
最长公共子序列:
给定两个序列,求序列最长的公共子序列,
如a=[1,2,3,4,5,6] b=[4,5,6,1,2,4]对于a b来说,最长公共子序列长度为3,有两个解[4,5,6][1,2,4]
可以设二维数组dp,横轴表示b纵轴表示a,即dp[1]表示到4为止的最长公共子序列,dp[2]表示[4,5]的最长公共子序列,以此类推
迭代下去,对于a来说,则是每次读入一个值比较,比如读入1,则显然dp[1][1]=dp[1][2]=dp[1][3]=0 dp[1][4]=dp[1][5]=dp[1][6]=1
通过不断读入a的值从左到右更新dp数组,最后dp[m][n]即为所求的最长公共子序列
当a[i]==b[j]时,可以从dp[i-1][j-1]推出dp[i][j],因为多匹配了上了一个所以dp[i][j]=dp[i-1][j-1]+1
当不相等时,dp[i][j]=max(dp[i-1][j],dp[i][j-1])
匹配不上,所以应该从对于a中1到 i 的元素、b中 1 到(j-1)的最长公共子序列dp[ i ][ j-1 ]与
a中1到(i-1)的元素、b中1到 j 的最长公共子序列dp[ i-1][ j ]比较更新dp[ i ][ j ]的值
时间复杂度为O(m*n)
int i,j; for(i=1;i<=m;i++) for(j=1;j<=n;j++) { if(a[i]==b[j]) dp[i][j]=dp[i-1][j-1]+1 else dp[i][j]=max(dp[i-1][j],dp[i][j-1]); }
最长递增子序列:
给定一个序列,求最长递增子序列
对于a = [ 2 ,5 ,6, 3,4, 5]来说最长递增子序列即[2 ,3, 4, 5]
1 int i,j; 2 for(i=1;i<=m;i++) 3 { 4 dp[i]=1; 5 for(j=1;j<i;j++) 6 { 7 if(a[i]>a[j]) 8 dp[i]=max(dp[i],dp[j]+1) 9 } 10 }
最朴素的思想就是O(m^2)对于每次读入的a[ i ]值以a[ j ]( i < j)比较,若a[ i ]>a[ j ] 则dp[ i ]可以取dp[ j ]+1
但是不一定dp [ i ]就比dp [ j ]+1小,所以要做个选择,上例子中用a [4 ]=3更新dp数组时,显然dp[ 4]最大只能更新为2
而dp[ 3]此时已经为3(2,5,6)在之后若来个7,dp[ i ]先扫到dp[3]则会更新为4显然比扫到dp[ 4 ]时要大
不要忘了先将dp[ i ]置1,因为即使a[ i ]是最小的,最长递增子序列也至少为1而不是0
如果只关注最长递增子序列长度,也可以使用二分搜索来优化,达到O(nlogn)的时间复杂度
1 const int inf=0x3f3f3f3f; 2 int i,j,ans=0; 3 memset(dp,inf,sizeof(inf)); 4 for(i=1;i<=n;i++) 5 { 6 j=lower_bound(dp+1,dp+1+n,a[i])-dp; 7 dp[j]=a[i]; 8 } 9 i=1; 10 while(dp[i]!=inf) 11 ans++,i++; 12 cout<<ans<<endl;
先把dp数组置为一个很大的数,每次读入a[i]都用lower_bound(二分,在[1,n+1)中找到第一个大于等于a[i]的值,返回该值的地址)更新dp数组
此时数组中非等于inf的元素个数即为最长递增子序列,例如对于
a=[2,5,6,3,4,5]
在读入a[3]时dp=[2,5,6,inf....]此时在读入a[4] dp=[2,4,6,inf...]虽然在dp数组中4跑到6前面
但是由于我们只关心最长递增子序列长度,所以不影响
后续读到最后一个5时dp数组就会更新为dp=[2,3,4,5,inf,inf....]
若再来个1则变成dp=[1,3,4,5,inf,inf...]显然来个1后最长递增子序列长度依然为4
最长公共递增子序列:
给定两个序列,求最长公共递增子序列。求这个不能通过先求两个最长递增子序列,再求最长公共子序列的方法
因为最长公共递增子序列不一定在最长递增子序列里,例如
a=[,6,7,1,2,3,4]
b=[11,12,13,14,6,7]
1 int i ,j; 2 int tmp; 3 for(i=1;i<=m;i++) 4 { 5 tmp=0; 6 for(j=1;j<=n;j++) 7 { 8 if(a[i]>b[j]) 9 tmp=max(tmp,dp[j]); 10 else if(a[i]==b[j]) 11 dp[j]=tmp+1; 12 } 13 }
dp[ i ]表示对于b数组1到 i 的最长递增子序列,遍历a中元素不断更新dp值
对于 i > j 若有 a[ i ]==b[ i ] 那么dp[ i ]=tmp+1
tmp=max(dp [ j ])
浙公网安备 33010602011771号