题目描述:
给你一个字符串 s
,找到 s
中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
示例 1:
输入:s = "babad" 输出:"bab" 解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd" 输出:"bb"
算法一:
思路:
回文串两边去掉还是回文串,并使用动态规划dp[i][j]来判断s[i...j]是否是回文串
代码实现:
//对于一个子串而言,如果它是回文串,并且长度大于 222
//那么将它首尾的两个字母去除之后,它仍然是个回文串
class Solution
{
public:
string longestPalindrome(string s){
int n=s.size();
if(n<2){
return s;
}
int left,right,len;
int begin=0,max=1;//返回字串的头尾
// dp[i][j] 表示 s[i..j] 是否是回文串
vector<vector<int>> dp(n,vector<int>(n));
for(int i=0;i<n;i++) dp[i][i]=1;
//枚举字串的长度len
for(len=2;len<=n;len++){
for(left=0;left<len;left++){
//right-left+1=len
right=len+left-1;
//right越界
if(right>=n) break;
//不为回文子串
if(s[left]!=s[right]) dp[left][right]=0;
//是回文子串
else{
//长度小于4(1,2,3)
//如 aba,aa,a
if(len<4) dp[left][right]=1;
//
else{
//只有s[i+1:j−1]是回文串,并且s的第i和j个字母相同时
//s[i:j]才会是回文串。
//所以不能写成dp[left][right]=1
//因为这只满足了第i和j个字母相同
dp[left][right]=dp[left+1][right-1];
}
}
//更新头尾
if(dp[left][right]==1&&max<len){
max=len;//从头开始需要遍历的长度
begin=left;//头
}
}
}
return s.substr(begin,max);
}
};
算法二:
思路:
从中心开始向两边扩展,并考虑中心是奇数还是偶数
代码实现:
class Solution
{
public:
pair<int,int> expandSubstr(const string &s,int left,int right){
//向中心两边扩展
while(left>=0 && right<s.size() && s[left]==s[right]){
--left;
++right;
}
//返回不符合情况的字串的前一个字串,故要left加回1,right减回1
return {left+1,right-1};
}
string longestPalindrome(string s){
int start=0,end=0;
for(int i=0;i<s.size();i++){
auto [left1,right1] = expandSubstr(s,i,i);//中心为奇数的字串
auto [left2,right2] = expandSubstr(s,i,i+1);//中心为偶数的字串
//分类
if(right1-left1>end-start){
end = right1;
start = left1;
}
if(right2-left2>end-start){
end = right2;
start = left2;
}
}
return s.substr(start,end-start+1);
}
};
算法三:Manacher算法
还在学习中,之后补充代码