题目:给定一个字符串s,你可以从中删除一些字符,使得剩下的串是一个回文串。如何删除才能使得回文串最长呢?
输出需要删除的字符个数。
思路:提到回文串,自然要利用回文串的特点,想到将源字符串逆转后,“回文串”(不一定连续)相当于顺序没变
求原字符串和其反串的最大公共子序列(不是子串,因为可以不连续)的长度(使用动态规划很容易求得),然后用原字符串的长度减去这个最大公共子串的长度就得到了最小编辑长度。
最长公共子序列的动态规划递推方程:
代码:
#include<iostream>
#include<string>
#include<vector>
using namespace std;
//计算公共子序列长度
void LCS(string s1,string s2) {
int size1 = s1.size()+1;
int size2 = s2.size()+1;
vector<vector<int>> matrix(size1, vector<int>(size2));
//初始化边界
for (size_t i = 0; i < size1; i++)
{
matrix[i][0] = 0;
}
for (size_t j = 0; j < size2; j++)
{
matrix[0][j] = 0;
}
//递推
for (size_t i = 1; i < size1; i++)
{
for (size_t j = 1; j < size2; j++)
{
if (s1[i-1] == s2[j-1])
matrix[i][j] = matrix[i - 1][j - 1]+1;
else {
if (matrix[i - 1][j] < matrix[i][j - 1])
matrix[i][j] = matrix[i][j - 1];
else
matrix[i][j] = matrix[i - 1][j];
}
}
}
cout << s1.size() - matrix[size1 - 1][size2 - 1]<<endl;
}
int main() {
string s;
while (cin >> s) {
int len = s.size();
char* rev = new char[len + 1];
//反转字符串
for (size_t i = 0; i < len; i++)
{
*(rev + i) = s[len - 1 - i];
}
*(rev + len) = '\0';
string s2(rev);
//s2是s反转后的字符串,这两个字符串的最长公共子序列就是s的最长的回文序列
LCS(s, s2);
}
}