最长公共子序列LCS+最长递增子序列LIS+最长递增公共子序列LICS

时间:2020-04-11
本文章向大家介绍最长公共子序列LCS+最长递增子序列LIS+最长递增公共子序列LICS,主要包括最长公共子序列LCS+最长递增子序列LIS+最长递增公共子序列LICS使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

最长公共子序列(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\n",t=LCIS());
47         if(t)
48             printf("\n");
49       for(int i=0;i<t;i++)cout<<f[t]<<endl;
50     return 0;
51 }

原文地址:https://www.cnblogs.com/randy-lo/p/12679166.html