LCS最大子序列(不连续)
本来南昌预选赛最后一题百度了相关算法 结果弹出的都是lcs,就看了下,原来是简单的动态规划。
51nod1006
1006 最长公共子序列Lcs
1 秒 131,072 KB 0 分 基础题
给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的)。
比如两个串为:
abcicba
abdkscab
ab是两个串的子序列,abc也是,abca也是,其中abca是这两个字符串最长的子序列。
输入
第1行:字符串A
第2行:字符串B
(A,B的长度 <= 1000)
输出
输出最长的子序列,如果有多个,随意输出1个。
输入样例
abcicba
abdkscab
输出样例
abca
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 1005;
int dp[maxn][maxn]; //所需数组
char x[maxn],y[maxn];
int lcs(char a[],char b[])//lcs返回最大子序列的长度
{
int alen=strlen(a);
int blen=(strlen(b));
for(int i=1;i<=alen;i++)
{
for(int j=1;j<=blen;j++) //为了dp初始不用考虑边界 dp【i】【j】对应 前i位和前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]);
}
}
return dp[alen][blen];
}
void printlcs(char res[]) //回溯找那个最大子序列,把结果存在res数组
{
int xlen=strlen(x);
int ylen=(strlen(y));
int size=dp[xlen][ylen];
res[size]='\0';
int i=xlen,j=ylen; //初始
while(i&&j)
{
if(x[i-1]==y[j-1]&&dp[i][j]==dp[i-1][j-1]+1) //注意dp里存的是第几位,在原数组里面是第n-1位
{
res[--size]=x[i-1];
i--;
j--;
}
else
{
if(dp[i-1][j]>dp[i][j-1])
i--;
else
j--;
}
}
}
int main()
{
gets(x);gets(y);
lcs(x,y);
char ans[maxn];
printlcs(ans);
cout<<ans;
}
参考文章:https://blog.csdn.net/synapse7/article/details/11720559
南昌网络赛最后一题,判断是否是子字符序列,注意这里的序列可以不连续。
看懂师兄的代码,才知道,实际上就是开个数组,使得之后判断的字符串每个字符可以不断地跳,就是说记录了这个字符会是在源字符串的第几位,从而不断地跳,只需遍历判断的字符串即可。代码如下:
#include<bits/stdc++.h>
using namespace std;
int a[100000][130],b[130];
int main()
{
string s;
ios::sync_with_stdio(false);
getline(cin,s);
memset(b,-1,sizeof(b));
for(int i=s.size()-1;i>=0;i--)
{
memcpy(a[i],b,sizeof(b)); //拷贝内存
b[s[i]]=i; // 之后才变,所以a【0】记录的是后n-1位。
}
int T;
cin>>T;
cin.get();
while(T--)
{
string t;
getline(cin,t);
int j=1;
int k=b[t[0]]; //这个时候b所有都记录了
for(;j<t.size();j++)
{
if(k==-1)break;
k=a[k][t[j]];
}
if(j>=t.size() && k!=-1)cout<<"YES"<<endl;
else
cout<<"NO"<<endl;
}
return 0;
}
另外一个博客可参考 :https://blog.csdn.net/WHY995987477/article/details/89425681