最长公共子序列:
给定两个字符串str1和str2,输出两个字符串的最长公共子序列。如果最长公共子序列为空,则返回"-1"。目前给出的数据,仅仅会存在一个最长的公共子序列
示例1
输入:
"1A2C3D4B56","B1D23A456A"
复制返回值:
"123456"
解题思路:

#include<iostream>
#include<algorithm>
#include<string.h>
char a[1001],b[1001];
int lcs[1001][1001];
using namespace std;
main()
{
gets(a+1);//为了更加方便所以从1开始取值,例如你输入hnucm a[0]是空格,a[1]才是h,这就
//更好的操作和使用
gets(b+1);
string dp="";
int l1=strlen(a+1);
int l2=strlen(b+1);
for(int i=0;i<=l1;i++)
for(int j=0;j<=l2;j++)
{ if(i==0||j==0) lcs[i][j]=0;
else if(a[i]==b[j]) lcs[i][j]=lcs[i-1][j-1]+1;
else lcs[i][j]=max(lcs[i-1][j],lcs[i][j-1]);
}
int ans=l1,bns=l2,num=0;
while(ans!=0&&bns!=0)//恢复最长公共序列,相当于从一串字符串中找到A、B两串中共有的字符,这里从A串中还原最长公共字符串
{
if(lcs[ans][bns]!=lcs[ans-1][bns])//lcs[i][j]来自于lcs[i][j-1]或者lcs[i-1][j-1],不管来自哪个,Ax肯定包含在最长公共字符串中
{
dp=dp+a[ans];//记录最长公共串
ans--;//继续判断A串中前一个字符
bns--;//不管By来自与哪个表达式,By已经被判断过了,现在应该继续B的前一个字符
}
else if(lcs[ans][bns]==lcs[ans][bns-1])//如果来自lcs[i][j-1],那么说明By不包含在最长公共字符串中,继续遍历B的前一个字符
bns--;
else ans--;//说明Ax不包含在最长公共字符串中,继续遍历A的前一个字符
}
reverse(dp.begin(),dp.end());//因为给dp赋值时就是倒着来的
cout<<dp;
}
牛客AC代码:
注意上述图片中是重下标1开始的哦!!!!
class Solution {
public:
/**
* longest common subsequence
* @param s1 string字符串 the string
* @param s2 string字符串 the string
* @return string字符串
*/
string LCS(string s1, string s2) {
// write code here
int lcs[2000][2000];
string dp="";
int l1=s1.size();
int l2=s2.size();
if(l1==0||l2==0)return "-1";
for(int i=1;i<=l1;i++)
for(int j=1;j<=l2;j++)
{
if(i==0||j==0)lcs[i][j]=0;
else if(s1[i-1]==s2[j-1]) lcs[i][j]=lcs[i-1][j-1]+1;//注意这里和上一个代码的区别
else lcs[i][j]=max(lcs[i-1][j],lcs[i][j-1]);
}
int ans1=l1,ans2=l2;
while(ans1!=0&&ans2!=0){
if(lcs[ans1][ans2]!=lcs[ans1-1][ans2]){
dp=dp+s1[ans1-1]; //因为牛客中是直接一个字符串,所以我们就必须要和前面的保持一致
ans1--;
ans2--;
}
else if(lcs[ans1][ans2]==lcs[ans1][ans2-1])
ans2--;
else ans1--;
}
if(dp.size()==0)return "-1";
reverse(dp.begin(),dp.end());
return dp;
}
};
回文串:
对给定的字符串,本题要求你输出最长对称子串的长度。例如,给定Is PAT&TAP symmetric?,最长对称子串为s PAT&TAP s,于是你应该输出11。
输入格式:
输入在一行中给出长度不超过1000的非空字符串。
输出格式:
在一行中输出最长对称子串的长度。
输入样例:
Is PAT&TAP symmetric?
输出样例:
11
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
string str;
getline(cin,str);//读入空格,不能用cin
int res=0;
for(int i=0;i<str.size();i++)//注意下面两种情况必须是一起的,为什么呢,因为题目中含有空格,而空格会影响最大的对称长度,你可以试一试
{
int l=i-1,r=i+1;//长度是奇数的情况
while(l>=0&&r<str.size()&&str[l]==str[r]) //l r没有出界
l--,r++;//l向左走 r向右走
res=max(res,r-l-1);//长度是r-l+1 -2(减去两边不对称的l r)=r-l-1
l=i,r=i+1;//长度是偶数的情况
while(l>=0&&r<str.size()&&str[l]==str[r])
l--,r++;
res=max(res,r-l-1);
}
cout<<res<<endl;
return 0;
}
再来一个回文串

对字符串
s[i..j],最少需要进行dp[i][j]次插入才能变成回文串。当i == j时dp[i][j] = 0,因为当i == j时s[i..j]就是一个字符,本身就是回文串,所以不需要进行任何插入操作。
int minInsertions(string s) {
int n = s.size();
// 定义:对 s[i..j],最少需要插入 dp[i][j] 次才能变成回文
vector<vector<int>> dp(n, vector<int>(n, 0));
// base case:i == j 时 dp[i][j] = 0,单个字符本身就是回文
// dp 数组已经全部初始化为 0,base case 已初始化
// 从下向上遍历
for (int i = n - 2; i >= 0; i--) {
// 从左向右遍历
for (int j = i + 1; j < n; j++) {
// 根据 s[i] 和 s[j] 进行状态转移
if (s[i] == s[j]) {
dp[i][j] = dp[i + 1][j - 1];
} else {
dp[i][j] = min(dp[i + 1][j], dp[i][j - 1]) + 1;
}
}
}
// 根据 dp 数组的定义,题目要求的答案
return dp[0][n - 1];
}
本文介绍了如何求解两个字符串的最长公共子序列,通过动态规划实现,给出了示例代码。同时,讲解了判断字符串对称性的方法,以及计算使字符串变为回文串所需的最小插入次数的算法。内容涵盖字符串处理和动态规划基础。

523

被折叠的 条评论
为什么被折叠?



