题目要找一个字符串数组中最长的回文子序列,首先如果定义传统的dp[i]
表示0到i最长的回文子序列,则要求的结果是dp[len-1],但是由0到i-1推得i就显得不太容易了,因为我们不知道i要放到前面的哪个最长回文子序列里,这个可以通过枚举小于i的j,但是对于能不能放就麻烦了,因为放进一个i还要构成一个回文,这就要和回文的第一个字符作判断,而这种dp定义是没法判断的。第二种定义,定义dp[i]为,以第i个字符结尾的最长回文子序列,则同样遇到第i个字符与前面的到底能不能构成回文这个问题,也要考虑回文的第一个字符。自然想到了定义dp[i][j]为i到j的最长回文子序列,如果s[i]==s[j],则dp[i][j]=dp[i+1][j-1]+2,如果s[i]!=s[j],dp[i][j]=max(dp[i+1][j],dp[i][j-1]),而我们这个dp只用到了上三角矩阵,所以下三角矩阵式空着的。对于i等于j的情形dp值就为1,对于j等于i+1的情形,如果s[i]和s[j]相等,则dp为2,否则为1,如果下三角矩阵初始化为0,则以上两种可以放到dp递推式中。这个dp中要注意,递推要从底部向上推
因为子问题是从dp[5][5],dp[4][4],dp[4][5]这样子开始的
int longestPalindromeSubseq(char * s){
int len=strlen(s);
int dp[len][len];
for(int i=len-1;i>=0;i--)
{
for(int j=i;j<len;j++)
{
if(j==i)
dp[i][j]=1;
else if(j-i==1)
{
if(s[i]==s[j])
{
dp[i][j]=2;
}
else
{
dp[i][j]=1;
}
}
else
{
if(s[i]==s[j])
{
dp[i][j]=dp[i+1][j-1]+2;
}
else
{
dp[i][j]=dp[i+1][j]>dp[i][j-1]?dp[i+1][j]:dp[i][j-1];
}
}
}
}
return dp[0][len-1];
}
然后评论区里还有将这个字符串倒置,求最长公共子序列的做法
然后 也可以进行空间的优化,因为上一行的结果只用到了下一行的结果