您的位置:首页 > 其它

【LeetCode 214】最长回文子串

2016-05-06 13:07 573 查看
题目链接:


https://leetcode.com/problems/shortest-palindrome/
题目描述:

给一个字符串s, 求在其前方添加最少的字符使添加后的s是回文串,并返回该回文串。

例如:

输入:1221abc

输出:cba1221abc

输入:121abc

输出:cba121abc

思路:

其实就是求从第一个字母开始,满足最长的回文串。

s = 最长从第一个字母开始的回文串 + 尾巴

ans = 尾巴的逆序 + s

所以,问题转化为求s的最长子回文串

最长回文字串:

暴力法:

定中心,从中心+-0开始 到两端扩展,判断是否回文串,O(n^2),超时

Manacher算法:

 从左到右边定中心,从中心+-p[中心]开始向两端扩展, 时间复杂度O(n), 详见前一篇博客 【最长回文子串】Manache算法

回文串两种形式,统一为一种形式

因为回文串有两种形式,

121,奇数

1221,偶数

通过加入符号可以都转换为奇数的情况

121      ->     #1#2#1

1221    ->    #1#2#2#1#

用转换后的字符换进行处理,求完后再求出,在原字符串的起点,长度即可

实现:

#include<string>
#include<iostream>
#include<vector>
using namespace std;

class Solution {
public:
string shortestPalindrome(string s) {
int i, j;
string s2 = "#";
for (i = 0; i < s.length(); i++) {
s2 += s.at(i);
s2 += "#";
}
vector<int> p = manacher(s2);

int cen = 0;
for (i = 0; i < p.size(); i++) {
if(i - p[i] == 0) {
cen = i;
}
}

int maxL = p[cen];
string head = "";
for (j = s.length() - 1; j >= maxL; j--) {
head += s.at(j);
}
s = head + s;
return s;
}

vector<int> manacher(string s) {
int l, r;
int len = s.length();
int cen = 0;
vector<int> p;
p.push_back(0);

for (r = 1; r < len; r++) {
// printf("cen = %d, pcen = %d, r = %d\n", cen, p[cen], r);
p.push_back(0);
int cenR = cen + p[cen];
if (r <= cenR) {
l = 2 * cen - r;
p[r] = p[l] < cenR - r ? p[l] : cenR - r;
} else {
p[r] = 0;
}

// 这里是关键,如果从r为中心长度为0开始向两边扩展,则复杂度为O(n^2), 这里从p[r]开始扩展
while((r-p[r]-1>=0) && (r+p[r]+1<len) && (s.at(r - p[r] -1) == s.at(r + p[r] + 1))) p[r]++;

if (r + p[r] > cenR) {
cen = r;
}
}

//cout << s << endl;
//int i;
//for (i = 0; i < len; i++) {
//	printf("%d ", p[i]);
//} printf("\n");
return p;
}
};
int main() {
Solution s;
string ans = s.shortestPalindrome("77777777777777777777777777777777777777771");
cout << ans << endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: