【问题描述】
给定一个字符串s,找到其中最长的回文子序列。可以假设s的最大长度为1000。
示例 1:
输入:
“bbbab”
输出:
4
一个可能的最长回文子序列为 “bbbb”。
示例 2:
输入:
“cbbd”
输出:
2
一个可能的最长回文子序列为 “bb”。
【思路】
我一开始完全是按照最长递增子序列的思路来的,唯一的区别就是维护了一个start数组来存放每个回文序列的起始字符下标位置。因为根据回文序列的性质,最后一个字符一定要与第一个字符相等,如果相等就代表可以作为回文序列的一员嘛
于是写出了以下代码:
class Solution {
public:
int dp[1005]; //dp[i]表示以i结尾的最长回文子序列的长度
int start[1005];
int longestPalindromeSubseq(string s) {
int length = s.size();
if(length == 0) //空串的坑
return 0;
//先赋初值
for(int i = 0;i < length;i++)
{
dp[i] = 1;
start[i] = i;
}
for(int i = 1;i < length;i++)
{
for(int k = 0;k < i;k++)
{
if(s[i] == s[start[k]]) //回文串性质:最后一个字符必须和开头的字符相同
{
dp[i] = max(dp[i], dp[k] + 1);
start[i] = start[k]; //这句差点写掉
}
}
}
//最后扫描一遍dp数组,找出最大值
int max_res = dp[0];
for(int i = 1;i < length;i++)
{
max_res = max(max_res, dp[i]);
}
return max_res;
}
};
然鹅,答案错误!发现是aabaa这种情况死活解决不了。。。
想了一会儿还是没啥思路,查查吧。发现竟然。。。根据回文子序列的性质,将原字符串s逆序一下得到字符串t, 然后求两者的最长公共子序列就可以了,我。。。。
不得不说,这个思路确实清奇,我没想到。以后回文序列的题可以考虑用这种思路,是个启发
Ac代码:
class Solution {
public:
int dp[1001][1001];
int longestPalindromeSubseq(string s) {
if(s == "")
return 0;
int length = s.size();
//反序
string t = s;
reverse(t.begin(), t.end());
for(int j = 0;j < length;j++)
{
if(t[0] == s[j])
{
for(int k = j;k < length;k++)
{
dp[0][k] = 1;
}
break;
}
}
for(int j = 0;j < length;j++)
{
if(s[0] == t[j])
{
for(int k = j;k < length;k++)
{
dp[k][0] = 1;
}
break;
}
}
for(int i = 1;i < length;i++)
{
for(int j = 1;j < length;j++)
{
if(t[i] == s[j])
dp[i][j] = dp[i - 1][j - 1] + 1;
else
dp[i][j] = max(dp[i][j - 1], dp[i - 1][j]);
}
}
/*
for(int i = 0;i < length;i++)
{
for(int j = 0;j < length;j++)
{
cout << dp[i][j] << " ";
}
cout << endl;
}*/
return dp[length - 1][length - 1];
}
};