题目
给你一个字符串 s
,找到 s
中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
思路一(动态规划)
dp[i][j]表示s[i]到s[j]所表示的子串是否是回文子串,是则为1,不是则为0。根据s[i]是否等于s[j],可以把转移情况分为两类:
一、若s[i]==s[j],那么只要s[i+1]至s[j-1]是回文子串,s[i]至s[j]就是回文子串,如果s[i+1]至s[j-1]不是,则s[i]至s[j]就不是回文子串。
二、若s[i]!=s[j],那么s[i]至s[j]一定不是回文子串
代码实现如下(c++):
class Solution {
public:
string longestPalindrome(string s) {
int n=s.size();
int dp[n+1][n+1];
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
//dp数组初始化为0
dp[i][j]=0;
}
}
string ans;
for(int i=0;i<n;i++){
dp[i][i]=1;
if(s[i]==s[i+1]){
dp[i][i+1]=1;
//初始化时注意当前最长回文长度
ans=s.substr(i,2);
}
string s2=s.substr(i,1);
if(s2.size()>ans.size()){
ans=s2;
}
}
for(int L=3;L<=n;L++){ //枚举子串长度
for(int i=0;i+L-1<n;i++){ //枚举子串开始节点
int j=i+L-1; //子串的右端点
// 每当计算dp[i][j]时,由于我们是按照子串长度从小到大计算的,因此dp[i+1][j-1]必为已知
if(s[i]==s[j]&&dp[i+1][j-1]==1){
dp[i][j]=1;
string s1=s.substr(i,L);
if(s1.size()>ans.size()){
ans=s1; //更新最长回文子串
}
}
}
}
return ans;
}
};
思路二(双指针)
双指针在力扣上超出时间限制
分为两种情况:
一、有偶数个字符
二、有奇数个字符
如果回文串的长度为奇数,则它有一个中心字符;如果回文串的长度为偶数,则可以认为它有两个中心字符。
代码实现如下(java)
class Solution {
public String longestPalindrome(String s) {
int len=s.length();
String res=" ";
for(int i=0;i<len;i++){
//找以i为中心的最长字符串
String s1=Palindrome(s,i,i); //奇数字符的情况
String s2=Palindrome(s,i,i+1); //偶数字符的情况
res=res.length()>s1.length() ?res : s1;
res=res.length()>s2.length() ?res : s2;
}
return res;
}
//找到以s[i]到s[j]为中心的最长字符串
public String Palindrome(String s,int i,int j){
int left=i,right=j;
while(left>=0&&right<s.length()){
if(s.charAt(left)==s.charAt(right)){
// 向两边延展
left--;
right++;
}
}
return s.substring(left+1,right);
}
}