A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = < x1, x2, …, xm > another sequence Z = < z1, z2, …, zk > is a subsequence of X if there exists a strictly increasing sequence < i1, i2, …, ik > of indices of X such that for all j = 1,2,…,k, xij = zj. For example, Z = < a, b, f, c > is a subsequence of X = < a, b, c, f, b, c > with index sequence < 1, 2, 4, 6 >. Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y.
Input
The program input is from the std input. Each data set in the input contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct.
Output
For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line.
Sample Input
abcfbc abfcab
programming contest
abcd mnp
Sample Output
4
2
0
状态转移方程:
代码:
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
int dp[10005][10005];
int main()
{
string a,b;
while(cin>>a>>b)
{
for(int i=1;i<=a.size();++i)
{
for(int j=1;j<=b.size();++j)
{
if(a[i-1]==b[j-1]) dp[i][j]=dp[i-1][j-1]+1;
else dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
}
}
cout<<dp[a.size()][b.size()]<<endl;
}
return 0;
}
下面是利用LIS优化:
很明显这题的数据范围在1e5,用上面的O(n^2)的算法会TLE
所以要利用LIS优化,而且LIS也要用队列+二分进行优化,这样复杂度就会降到O(nlogn),但是使用这一优化方法的前提是两个数组中的元素均无重复且相同,具体优化的思路是啥呢,默认a数组的元素序列是有序的上升序列,然后将a数组中元素的映射也映射到b数组中,这样就得到了b数组中的每个元素在a数组中排第几位,然后对b数组做LIS即可。
下面是代码:
#include<iostream>
#include<cstdio>
#include<map>
#include<algorithm>
using namespace std;
typedef long long ll;
map<int,int> mp;
inline int read()
{
int s = 0, w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){ if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
int qu[100005];//队列
int a[100005],b[100005];
int qu_i=0,temp;
int main()
{
int n;
ll ans=0;
n=read();
for(int i=1;i<=n;++i)
{
a[i]=read();
mp[a[i]]=i;//做一个映射
}
for(int i=1;i<=n;++i)
{
b[i]=read();
b[i]=mp[b[i]];//映射到b,得到b的每个元素在a中是第几位
}
qu[qu_i++]=b[1];
for(int i=2;i<=n;++i)
{
if(b[i]>qu[qu_i-1]) qu[qu_i++]=b[i];//如果b[i]大于数列中最大的数字,则直接入队
else
{
temp=lower_bound(qu,qu+qu_i,b[i])-qu;//寻找队列中第一个大于等于b[i]的元素,注意返回值是地址,要得到数组下标则要减去数组首地址
qu[temp]=b[i];//替换那个元素,实际上是有贪心的成分在里面,因为替换了这个元素后,LIS的长度不变,但是在之后会有另一个元素加进来的几率增大了
}
}
cout<<qu_i<<endl;//输出队列长度即为答案
return 0;
}