题目描述:给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。
示例 1:
输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
示例 2:
输入: "cbbd"
输出: "bb"
解题思路:
根据回文串的特性:我们知道一个字符串是回文那么同时去掉首尾一个字符仍然是回文(abcba同时去掉首尾的a,剩下的bcb仍然是回文),根据这个特性我们就可以列出他的状态转换方程。
我们设一个二维数组dp[i][j]来判断从下标 i 到下标 j 之间的字符串受否为回文.
要判断dp[i][j]是不是回文串需要先判断字符串两边的字符是否相等,如果相等判断dp[i+1][j-1]是不是回文串。
因为范围是i+1~~j-1;所以j-1-(i+1)+1>2,解得j-i<3;不满足那就说明越界或者不合法,之间忽视
(这里的串长度大于2,如果等于二就变成了判断dp[n][n]是不是回文串,自己本身就算,所以没什么意义)
举例:字符串arr="babc";下标为0~3
首先判断ba是否为回文,首先判断首尾是否相同,发现不同,那么ba这个子串的状态为false,所以bp[0][1]的状态为false;
然后判断bab是否为回文,首先判断首尾是否相同,相同则就同时去掉首尾然后判断剩下的子串是否为回文,去掉首尾剩下a,剩下的单个字符是回文,所以说明bab是回文,也就是说bp[0][2]的状态为true代表是回文。这时我们要记录这个回文串的长度maxlen,长度mexlen为j-1-(i+1)+1,把这个长度和原来的maxlen做对比取较大值,如果比原来的长那就说明原来的不是最长的我们做替换。同时需要记录回文的起始下标(根据长度和起始下标可以打印回文串)
然后判断ad是否为回文,首先ab的首尾不同,所以dp[1][2]的状态就是false,直接跳过
然后判断babc是否为回文,首先首尾不同,那么dp[0,3]状态为false,直接跳过
然后判断abc是否为回文,首先首尾不同,那么dp[1,3]状态为false,直接跳过
然后判断bc是否为回文,首先首尾不同,那么dp[2,3]状态为false,直接跳过
我们把所有的可能遍历完了,现在结果就是最长子串的长度就是maxlen,然后根据起始下标和长度打印出这个回文串。
下面给大家上正菜
#include<iostream>
#include<string>
#include<vector>
using namespace std;
class Solution {
public:string longestPalindrome(string s) {
int len=s.size();
if(len-2<0)
{
return s;
}
int maxlen=1;
int begin=0;
int **arr=new int*[len];//开辟一个二维数组保存状态
for(int i=0;i<len;i++)
{
arr[i]=new int[len];
}
for(int k=0;k<len;k++)
{
arr[k][k]=1;
}
for(int j=1;j<len;j++)
{
for(int i=0;i<j;i++)
{
if(s[i]!=s[j])//判断首尾是否相同,不同则把状态定义为0;
{
arr[i][j]=0;
}
else//首尾相同时,就要去掉同时去掉首尾判断是不是为回文;
{
if(j-i<3)//判断边界,因为现在首尾相同,所以最少范围的长度无论是1或者2或者3都是回文,自己想想为什么
{
arr[i][j]=1;
}
else
{
arr[i][j]=arr[i+1][j-1];
}
}
if(arr[i][j] && j-i+1>maxlen)//如果现在i~j下标的字符串是回文,且长度大于之前的回文长度时那么就要进行更新。
{
maxlen=j-i+1;
begin=i;
}
}
}
return s.substr(begin,maxlen);
}
};
int main()
{
string arr="bb";
Solution a ;
string res="";
res=a.longestPalindrome(arr);
printf("%s\n",res.c_str());
}