题目:
给定一个字符串s,你可以从中删除一些字符,使得剩下的串是一个回文串。如何删除才能使得回文串最长呢?输出需要删除的字符的个数。
思路:
先求字符串s的反转串rs,然后求s和rs的最大公共子序列(子序列不要求连续而子串要求连续,字符串和其反转串的最大公共子序列一定是对称的),则最大公共子序列的长度即为最大回文串的长度
最长公共子序列LCS 参考链接
1. 子序列
一个序列A中任意删除若干项,剩余的序列叫做A的一个子序列,也可以认为是从序列A按原顺序保留任意若干项得到的序列,对于一个长度为n的序列,它一共有2^n个子序列(子序列不是子集,它和原始序列的元素顺序相关)
2. 公共子序列
如果序列C既是A的子序列,也是B的子序列,则称其为A和B的公共子序列,空序列是任何两个序列的公共子序列
3. 最长公共子序列
A和B的公共子序列中长度最长的叫AB的最长公共子序列,最长公共子序列的不唯一
4. LCS算法-使用动态规划求解
·A有n个元素,B有m个元素,用Ax表示序列A的连续前x项构成的子序列,即Ax=a1,a2…ax,By=b1,b2…by,用LCS(x,y)表示它们的最长公共子序列长度,用L(x,y)表示Ax和By的一个最长公共子序列,原问题就等价于求LCS(m,n)。
(1) 当Ax=By=t时,其L(Ax,By)的最后一项一定为t,假设L(x,y)最后一项不是t,则要么L(x,y)为空序列,要么Aa=Bb≠t,且a<x,b<y。无论哪种情况都可以把t接到L(x,y)后面得到更长的公共子序列。如果从Ax中删掉最后一项ax得到Ax-1,从By中删掉最后一项by得到By-1,则从L(x,y)中也删掉最后一项t得到的序列时L(x-1,y-1)。因此有:
LCS(Ax,By)=LCS(x-1,y-1)+1
(2) Ax≠By时,假设t=L(Ax,By)或者L(Ax,By)是空序列
如果t≠Ax,则有L(x,y)=L(x-1,y),LCS(x,y)=LCS(x-1,y)
如果t≠By,则有L(x,y)=L(x,y-1),LCS(x,y)=LCS(x,y-1)
所以有LCS(x,y)=max(LCS(x-1,y),LCS(x,y)=LCS(x,y-1))
(3) 所以有:
5. 代码:C++实现
#include<iostream>
#include<string.h>
using namespace std;
//递归的方法
//注意 A和B分别为输入的字符串前面加上一个' '空的字符,是为了解决边界问题.
int LCS(string A, string B, int x, int y)
{
if(x==0 || y==0) //边界
return 0;
else //非边界位置
{
if(A[x] == B[y]) //最后一个字符相同
return LCS(A, B, x-1, y-1) + 1;
else
return max(LCS(A, B, x, y-1), LCS(A, B, x-1, y));
}
}
int main()
{
string A = "BCBACABBACDX";
string B = "BCXYDADJL"; // A 和 B的LCS为BCAD
int x = A.length();
int y = B.length();
A = ' ' + A;
B = ' ' + B;
int result = LCS(A, B, x, y);
cout << result << endl;
return 0;
}
#include<iostream>
#include<string.h>
using namespace std;
//循环打表 的方式求LCS[x][y]
int main()
{
string A = "BCBACABBACDX";
string B = "BCXYDADJL"; // A 和 B的LCS为BCAD
int x = A.length();
int y = B.length();
A = ' ' + A;
B = ' ' + B;
int i, j;
int ** LCS = new int*[x+1];
for(i=0;i<=x;i++)
{
LCS[i] = new int[y+1];
for (j=0;j<=y;j++)
LCS[i][j] = 0; //LCS[i][j]用来存储
}
for(i=0;i<=x;i++)
for(j=0;j<=y;j++)
if(i==0 || j==0)
LCS[i][j] = 0;
else
{
if(A[i] == B[j])
LCS[i][j] = LCS[i-1][j-1] + 1;
else
LCS[i][j] = max(LCS[i-1][j], LCS[i][j-1]);
}
int result = LCS[x][y];
cout << result << endl;
return 0;
}
- 题目实现:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
string converseString(string str){
int size = str.size();
if (size < 2) return str;
int front = 0, rear = size - 1;
while(front < rear){
char temp = str[front];
str[front] = str[rear];
str[rear] = temp;
front++;
rear--;
}
return str;
}
int max(int a, int b){
return a>b ? a : b;
}
int GetLCS(string s1, string s2){
int size = s1.size();
int curMax = 0;
vector<vector<int> > DP(size + 1, vector<int>(size + 1, 0));
for (int i = 0; i <= size; i++)
{
DP[i][0] = 0;
DP[0][i] = 0;
}
for (int i = 1; i <= size; i++)
for (int j = 1; j <= size; j++){
if (s1[i - 1] == s2[j - 1])
DP[i][j] = DP[i - 1][j - 1] + 1;
else
DP[i][j] = max(DP[i][j - 1], DP[i - 1][j]);
if (DP[i][j] > curMax)
curMax = DP[i][j];
}
return curMax;
}
int core(string str){
string converseStr = converseString(str);
return str.size() - GetLCS(str, converseStr);
}
int main(int argc, char* argv[])
{
cout << core("google") << endl;
return 0;
}