原题链接
题目解析
给一个字符串s,求出它最长的回文子串之一。
回文串:逆序后与原字符串一样的字符串,如abcba
1 <= s.length <= 1000
s
仅由数字和英文字母组成
三种解法
动态规划
原理:记录任意两个点对应的子串是否能构成回文串。
判断条件:令 i > j ,对于s[i]到s[j]是否是回文串来说。在s[i]=s[j]的情况下:1.i和j紧密相连,2.i和j中间只有一个值,3.s[i-1]到s[j+1]是一个回文串满足这三个条件之一即可。
class Solution {
public:
string longestPalindrome(string s) {
int begin = 0, end = 0,n = s.size();
vector<vector<bool>>dp(1000,vector<bool>(1000,false));
for(int i = 1;i<n;i++)
{
for(int j = i-1 ; j >= 0 ;--j){
if((s[i]==s[j])&&((i-j<3)||(dp[i - 1][j + 1] == true)))
{
dp[i][j] = true;
if(i - j>end-begin)
{
end = i;
begin = j;
}
}
}
}
return s.substr(begin,end-begin+1);
}
};
时间复杂度o(n^2),空间复杂度o(n^2)
中心扩展
从左向右遍历s,对于每个下标来说,如果周围连续的n个字符构成的字符串是回文字符串的话便记录下来
class Solution {
public:
string longestPalindrome(string s) {
int n=s.size(),left=0,right = 0;
int begin = 0,end =0;
for(int i = 1;i<n;i++){
left = i-1,right=i+1;
while(left>=0&&right<n&&s[right]==s[left])
{
left--,right++;
}
if(end-begin<right-left-2){
end = right-1;
begin =left+1;
}
left = i-1,right=i;
while(left>=0 && right<n&&s[right]==s[left])
{
left--,right++;
}
if(end-begin < right-left-2){
end = right-1;
begin =left+1;
}
}
return s.substr(begin,end-begin+1);
}
};
时间复杂度o(n^2),空间复杂度o(1)
Manacher
上图来自leetcode的官方题解,我水平一般,就不去细讲了,简单说一下思路:
打个比方对于字符串abbbbbc来说,把中心拓展法求出来的数列成数组。
abbbbbc->1235311
对于倒数第三个b来说,左右的元素是对称的,所以不需要判断即可得出,第二个b和第四个b对应的值是一样的,这样的话就可以跳过第四个行这样不断地跳过那些可以被推导出来的值即可将时间复杂度降到o(n)
class Solution {
public:
void init(string& s) {
string tmp ="#";
for (auto& e : s) {
tmp.push_back(e);
tmp.push_back('#');
}
tmp.push_back('#');
swap(s, tmp);
}
int expand(string& s,int left,int right) {
while(left>=0&&right<s.size()&&s[left]==s[right])
left--,right++;
return (right-left-2)/2;
}
string longestPalindrome(string s) {
init(s);
int center = 0, len = 0, right = -1, n = s.size();
int begin = 0,end = -1;
vector<int> arm_len;
for (int i = 0; i < n; i++) {
len = 0;
if (i > right) {
len = expand(s,i,i);
}else{
int left = 2*center-i;
int min_arm_len = min(arm_len[left],right-i);
len = expand(s,i-min_arm_len,i+min_arm_len);
}
arm_len.push_back(len);
if(i+len>right){
center = i;
right = i + len;
}
if(len*2+1>end -begin){
begin = i-len;
end = i + len;
}
}
string ans;
for (int i = begin; i <= end; ++i) {
if (s[i] != '#') {
ans += s[i];
}
}
return ans;
}
};
时间复杂度o(n),空间复杂度o(n)
感谢观看!!!