https://leetcode.com/problems/shortest-palindrome/?tab=Description
思路1:Brute Force
问题的核心就在于如何快速找到以所给字符串第一个字符开始的最长回文串。一种暴力枚举的方案是,从后往前枚举可能的回文串的终点,检测是否发现回文串,是的话即可结束枚举。极端情况是,以第一个字符开始的最长回文串就是它本身,这种情况下需要扫描整个字符串(检测是否回文需要O(n))。
Time complexity: O(n^2)
Space complexity: O(1)
class Solution {
public:
string shortestPalindrome(string s) {
if (s.empty()) return "";
int max_len = 1;
for (int j = s.size() - 1; j > 0; --j) {
// determine if s[0...j] is palindrome
bool sign = true;
for (int l = 0, r = j; l < r; l++, r--) {
if (s[l] != s[r]) {
sign = false; break;
}
}
if (sign) {
max_len = j + 1; break;
}
}
string addstr = s.substr(max_len, s.size() - max_len);
reverse(addstr.begin(), addstr.end());
return addstr + s;
}
};
ps. 这种最暴力的方法可以AC,leetcode 276ms
思路2:Manacher's algorithm
著名的Manacher算法可以在线性时间内计算出一个字符串中所有以某字符为中心的最长回文串,具体的算法细节可以参见 (http://acm.uestc.edu.cn/bbs/read.php?tid=3258) 。对于本问题,须要找的是以某字符开始的最长回文串,在算法运行的时候每确定一个回文串之后判断一下其左边界是否对应该字符,是的话更新一下回文串长度即可。
Time complexity: O(n)
Space complexity: O(n)
class Solution {
public:
string shortestPalindrome(string s) {
if (s.empty()) return "";
int max_len = 1;
// Manacher's algorithm
string str = "$#";
for (char c : s) {
str.push_back(c);
str.push_back('#');
}
int mx = 0, id;
vector<int> p(str.size(), 0);
for (int i = 1; i < str.size(); ++i) {
if (mx > i)
p[i] = min(p[2*id-i], mx-i);
else
p[i] = 1;
for (; str[i+p[i]] == str[i-p[i]]; p[i]++);
if (p[i] + i > mx) {
mx = p[i] + i;
id = i;
}
// update max_len start from the frist char
if (i-p[i]+1 == 1) max_len = p[i] - 1;
}
string addstr = s.substr(max_len, s.size() - max_len);
reverse(addstr.begin(), addstr.end());
return addstr + s;
}
};
ps. 该算法的性能明显比前一种强多了,leetcode 6ms