题目:
Given a string s, find the longest palindromic substring in s.
You may assume that the maximum length of s is 1000.
例子:
Example1:
Input: "babad"
Output: "bab"
Note: "aba" is also a valid answer.
Example2:
Input: "cbbd"
Output: "bb"
问题解析:
给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为1000。
链接:
- LeetCode:
思路标签
动态规划、中心扩展、Manacher法
解答:
1.动态规划 O(n^2)
- 利用动态规划的思想,将小问题逐步扩大到大问题,从而确定最长到回文字串;
- 保存子串,则保存回文子串到首字母的位置以及回文字串的长度;
- 定义dp[i][j]来表示字符串s[i]…s[j]的字串是否属于回文子串;
- 如果dp[i+1][j-1] = true && s[i] == s[j]则说明,s[i]…s[j]为回文子串,dp[i][j] = true.
class Solution {
public:
string longestPalindrome(string s) {
string emptystr = "";
int length = s.length();
if (length == 1)
return s;
if (length == 0)
return emptystr;
bool dp[1000][1000] = {false};
int maxsublength = 1;
int start = 0;
for (int i=0; i<length; ++i){
dp[i][i] = true;
if (i<length-1 && s.at(i) == s.at(i+1)){
dp[i][i+1] = true;
maxsublength = 2;
start = i;
}
}
for (int len=3; len <= length; ++len){
for (int i=0; i<=length-len; ++i){
int end = i + len - 1;
if (s.at(i) == s.at(end) && dp[i+1][end-1]){
dp[i][end] = true;
if (len > maxsublength){
maxsublength = len;
start = i;
}
}
}
}
return s.substr(start, maxsublength);
}
};
2. 中心扩展 O(n^2)
- 将字符串的每一个字母作为中心,向两边扩展,找到的最长的子回文串即可;
- 但是需要注意的是,我们需要分别考虑奇数和偶数的情况,如“aba”为奇数,”abba”为偶数。
class Solution {
public:
string longestPalindrome(string s) {
const int length = s.size();
string emptystr = "";
if (length == 0)
return emptystr;
int maxlength = 1;
int start = 0;
//回文串为奇数个数的情况
for (int i=0; i<length; ++i){
int head = i-1, tail = i+1;
while(head>=0 && tail<length && s.at(head) == s.at(tail)){
if (tail-head+1 > maxlength){
maxlength = tail-head+1;
start = head;
}
head--;
tail++;
}
}
//回文串为偶数的情况
for(int i=0; i<length; ++i){
int head = i, tail = i+1;
while(head>=0 && tail<length && s.at(head) == s.at(tail)){
if(tail-head+1 > maxlength){
maxlength = tail-head+1;
start = head;
}
head--;
tail++;
}
}
return s.substr(start, maxlength);
}
};
3. Manacher O(n)
- Manacher法只能解决例如aba这样长度为奇数的回文串,对于abba这样的不能解决,于是就在里面添加特殊字符。我是添加了“#”,使abba变为a#b#b#a。
- 这个算法就是利用已有回文串的对称性来计算的,具体算法复杂度为O(N)
#define min(x, y) ((x)<(y)?(x):(y))
#define max(x, y) ((x)<(y)?(y):(x))
string findLongestPalindrome3(string s)
{
int length=s.size();
for(int i=0,k=1;i<length-1;i++)//给字符串添加 #
{
s.insert(k,"#");
k=k+2;
}
length=length*2-1;//添加#后字符串长度
int *rad=new int[length]();
rad[0]=0;
for(int i=1,j=1,k;i<length;i=i+k)
{
while(i-j>=0&&i+j<length&&s.at(i-j)==s.at(i+j))
j++;
rad[i]=j-1;
for(k=1;k<=rad[i]&&rad[i-k]!=rad[i]-k;k++)//镜像,遇到rad[i-k]=rad[i]-k停止,这时不用从j=1开始比较
rad[i+k]=min(rad[i-k],rad[i]-k);
j=max(j-k,0);//更新j
}
int max=0;
int center;
for(int i=0;i<length;i++)
{
if(rad[i]>max)
{
max=rad[i];
center=i;
}
}
return s.substr(center-max,2*max+1);
}