最长公共子序列(LCS):两个串s1和s2中取出若干有序位置的字符,使得取出的两个字符串相同的长度的最大值就是LCS
最长递增子序列(LIS):S的子序列,其中各元素按索引严格单调递增
最长公共递增子序列(LCIS):上面两者的结合,参考博客:https://blog.csdn.net/wall_f/article/details/8279733
最长上升子序列的O(n^2)复杂度算法,算法的优势在于可以保存算法的转移,可以得出最后的序列。
代码如下:
1 #include<iostream> 2 using namespace std; 3 #define maxn 100 4 int n; 5 // 20 17 2 3 4 1 4 6 9 1 1 2 3 4 9 87 21 23 331 31 44 6 // 10 1 1 1 1 1 2 2 2 3 3 7 int a[maxn]; 8 int dp[maxn],from[maxn]; 9 void print (int pos) 10 { 11 if(!pos)return; 12 print(from[pos]); 13 cout<<a[pos]<<' '; 14 } 15 int main() 16 { 17 cin>>n; 18 for(int i=1;i<=n;i++)cin>>a[i]; 19 for(int i=1;i<=n;i++) 20 { 21 dp[i]=1;//以i为终止位置的最长上升子序列的长度 22 for(int j=1;j<i;j++) 23 { 24 if(a[i]>a[j]&&dp[i]<dp[j]+1) 25 { 26 dp[i]=dp[j]+1; 27 from[i]=j;//使dp[i]改变的最后一个位置 28 } 29 } 30 } 31 int ans=1,pos=1; 32 for(int i=1;i<=n;i++) 33 { 34 if(dp[i]>ans) 35 { 36 ans=dp[i];//记录len改变的最后一个位置 37 pos=i; 38 } 39 } 40 cout<<ans<<endl; 41 print(pos); 42 }
最长上升子序列的O(nlogn)算法, 中间结果无法保存,只能知道最长上升子序列的长度。其中加上一个辅助数组,数组的长度表示的是最长上升子序列的长度,数组中第i个位置保存的数是长度为i的最长上升子序列的末位最小元素,利用了贪心的思想,因为末尾的元素值越小的话留给下一个元素更新的余地就会更大。由于长度为n-1的最长上升子序列的末位元素一定是小于长度为n的最长上升子序列的末位元素,所以辅助数组的元素一定是有序的。
代码如下:
1 #include<iostream> 2 using namespace std; 3 #define maxn 100 4 #define INF 0x7ffffff 5 int n,l,r; 6 int a[maxn],dp[maxn];//dp[i]表示长度为i的最长上升子序列的末位元素最小值 7 int main() 8 { 9 cin>>n; 10 for(int i=1;i<=n;i++) 11 { 12 cin>>a[i]; 13 dp[i]=INF; 14 } 15 dp[1]=a[1]; 16 int len=1; 17 for(int i=2;i<=n;i++) 18 { 19 int mid; 20 l=0,r=len; 21 if(a[i]>dp[len])dp[++len]=a[i]; 22 else 23 { //二分查找 ,查找第一个大于a[i]的位置 24 while(l<r) 25 { 26 mid=(l+r)/2; 27 if(dp[mid]>a[i])r=mid; 28 else { 29 l=mid+1; 30 } 31 } 32 } 33 dp[l]=min(dp[l],a[i]); 34 } 35 cout<<len<<endl; 36 }
最长公共子序列算法如下:(包括对路径的保存)
1 #include <cstdio> 2 #include <iostream> 3 using namespace std; 4 int dp[1000][1000]; 5 int main() 6 { 7 string a,b; 8 while(cin>>a>>b) 9 { 10 for(int i=1;i<=a.size();i++) 11 for(int j=1;j<=b.size();j++) 12 { 13 if(a[i-1]==b[j-1])dp[i][j]=dp[i-1][j-1]+1; 14 else dp[i][j]=max(dp[i-1][j],dp[i][j-1]); 15 } 16 17 char path[1000]; 18 for(int aa=a.size(),bb=b.size(),num=1;aa>=1&&bb>=1;) 19 { 20 if(a[aa-1]==b[bb-1]) 21 { 22 path[num++]=a[aa-1]; 23 aa--,bb--; 24 } 25 else 26 { 27 if(dp[aa-1][bb]>dp[aa][bb-1]) 28 aa--; 29 else bb--; 30 } 31 } 32 cout<<dp[a.size()][b.size()]<<endl; 33 for(int i=dp[a.size()][b.size()];i>=1;i--) 34 cout<<path[i]<<" "; 35 cout<<endl; 36 } 37 return 0; 38 }
最长公共上升子序列算法:
1 #include<iostream> 2 #include<cstring> 3 #include<string> 4 using namespace std; 5 6 int max(int a,int b) 7 { 8 return a>b?a:b; 9 } 10 11 int a[1010],b[1010]; 12 int f[1010],n,m; 13 14 int LCIS() 15 { 16 int i,j,MAX; 17 memset(f,0,sizeof(f)); 18 for(i=0;i<n;i++) 19 { 20 MAX=0; 21 for(j=0;j<m;j++) 22 { 23 if(a[i]>b[j])MAX=max(MAX,f[j]); 24 if(a[i]==b[j])f[j]=MAX+1; 25 } 26 } 27 int ans=0; 28 for(i=0;i<m;i++) 29 ans=max(ans,f[i]); 30 return ans; 31 } 32 33 int main() 34 { 35 int t,i,j; 36 scanf("%d",&n); 37 for(i=0;i<n;i++) 38 { 39 scanf("%d",&a[i]); 40 } 41 scanf("%d",&m); 42 for(j=0;j<m;j++) 43 { 44 scanf("%d",&b[j]); 45 } 46 printf("%d ",t=LCIS()); 47 if(t) 48 printf(" "); 49 for(int i=0;i<t;i++)cout<<f[t]<<endl; 50 return 0; 51 }