题目:
描述
给定一个字符串s,找出其中最长的回文子序列,并返回该序列的长度。
子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。
输入
输入一个字符串s,长度不超过1000,全部由小写字母组成。
输出
最长回文子序列的长度。
样例输入
bbbab
样例输出
4
一道动态规划题,可以使用二维数组dp[i][j] 表示(注:这里i,j只是范围的表示字符,与接下来代码的i,j表示含义不同,以下的dp解释都是这样),i 表示区间左端 ,j 表示 区间右端 , 则dp[i][j]表示为字符串[i,j]范围中最长回文子序列。
那么这样的做法 初始化 怎么做呢?——dp[i][i]设为1(i属于字符串的总长度),单独的一个字符必然是回文串,且长度为1。
查找最长回文串的过程可以看成一个子串不断扩张的过程(可能向左,可能向右,也可能向两端)
状态转移方程:dp[i][j] 是表示[i,j]范围的回文串最值,可以遍历区间的左右端点 判断两端的字符是否相等 。
若相等 则说明回文串的长度肯定向左右各扩张了1单位,则dp[i,j]=dp[i+1,j-1]+2;
若不等 则说明回文串没有向两端扩张,那可能向左,也可能向右。但你不清楚是向哪边,那就取最值 dp[i][j] = max(dp[i+1][j], dp[i][j-1]);
代码(注释)
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
string x;
int dp[N][N];
int main()
{
cin>>x;
int len = x.size();
for(int i=0;i<len;i++) dp[i][i]=1;//单个字符是 长度为 1 的回文串
for(int i=1;i<len;i++) //这里的 i是区间的长度 从2开始
{
for(int j=0;j+i<len;j++)
{
if(x[j] == x[j+i]) // j表示左端点 j+i代表右端点 [j,j+i]表示区间
{
dp[j][j+i] = dp[j+1][j+i-1] + 2; // 说明回文序列向两端扩张了
}
else
{
dp[j][j+i] = max(dp[j+1][j+i], dp[j][j+i-1]); //从[j+1,k],[j,k-1] 选择 最大的 回文序列
}
}
}
cout << dp[0][len-1] << endl; //输出[0,len-1] 中 最大的回文序列
return 0;
}
代码(纯享版)
#include<bits/stdc++.h>
using namespace std;
const int N=1010;
string x;
int dp[N][N];
int main()
{
cin>>x;
int len = x.size();
for(int i=0;i<len;i++) dp[i][i]=1;
for(int i=1;i<len;i++)
{
for(int j=0;j+i<len;j++)
{
if(x[j] == x[j+i])
{
dp[j][j+i] = dp[j+1][j+i-1] + 2;
}
else
{
dp[j][j+i] = max(dp[j+1][j+i], dp[j][j+i-1]);
}
}
}
cout << dp[0][len-1] << endl;
return 0;
}
点个赞ba~ QWQ
THE END