516. 最长回文子序列
给你一个字符串 s ,找出其中最长的回文子序列,并返回该序列的长度。
子序列定义为:不改变剩余字符顺序的情况下,删除某些字符或者不删除任何字符形成的一个序列。
示例 1:
输入:s = “bbbab”
输出:4
解释:一个可能的最长回文子序列为 “bbbb” 。
示例 2:
输入:s = “cbbd”
输出:2
解释:一个可能的最长回文子序列为 “bb” 。
.............................................................................................................................................................
思路:
求字符串S(i,j) (i<= j 且0<i<s.size 0 < j < s.size)
是不是回文子序列,有几种情况
-
如果i==j,该串长度为1,且必定为回文序列,即
l e n ( S ( i , j ) ) = 1 len(S(i,j)) = 1 len(S(i,j))=1 -
如果字符串中的S(i) == S(j),那该字符串的回文序列长度必然等于子串s(i+1,j-1)的回文长度+2即
l e n ( S ( i , j ) ) = l e n ( s ( i + 1 , j − 1 ) ) + 2 len(S(i,j)) = len(s(i+1,j-1)) + 2 len(S(i,j))=len(s(i+1,j−1))+2 -
如果字符串中的S(i) != S(j), 那该字符串的回文序列长度必然等于子串s(i+1,j)与子串s(i,j-1)中的最长回文序列长度即
l e n ( S ( i , j ) ) = M a x ( l e n ( s ( i + 1 , j ) ) , l e n ( s ( i , j − 1 ) ) ) len(S(i,j)) = Max(len(s(i+1,j)),len(s(i,j-1))) len(S(i,j))=Max(len(s(i+1,j)),len(s(i,j−1)))
可得
l e n ( S ( i , j ) ) = { 1 , i = = j s ( i + 1 , j − 1 ) + 2 , S ( i ) = = S ( j ) M a x ( l e n ( s ( i + 1 , j ) ) , l e n ( s ( i , j − 1 ) ) , S ( i ) ! = S ( j ) len(S(i,j) )= \begin{cases} 1 ,\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad i==j \\ s(i+1,j-1) + 2,\quad\quad\quad\quad\quad\quad\quad\quad\quad S(i) == S(j)\\ Max(len(s(i+1,j)),len(s(i,j-1)),\quad S(i) != S(j) \end{cases} len(S(i,j))=⎩ ⎨ ⎧1,i==js(i+1,j−1)+2,S(i)==S(j)Max(len(s(i+1,j)),len(s(i,j−1)),S(i)!=S(j)
C++实现
int longestPalindromeSubseq(string s) {
int rows = s.size();
vector<vector<int>> dp(rows, vector<int>(rows, 0));
int max = 0;
for (int i = rows - 1; i >= 0; i--)
{
for (int j = 0; j < rows; j++)
{
if (i == j)
{
dp[i][j] = 1;
max = max < dp[i][j] ? dp[i][j] : max;
}
else if (j - i > 0)
{
if (s[i] == s[j])
{
dp[i][j] = dp[i + 1][j - 1] + 2;
max = max < dp[i][j] ? dp[i][j] : max;
}
else
{
dp[i][j] = dp[i + 1][j] > dp[i][j - 1] ? dp[i + 1][j] : dp[i][j - 1];
max = max < dp[i][j] ? dp[i][j] : max;
}
}
}
}
return max;
}