给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。
示例 1:
输入: "aacecaaa"
输出: "aaacecaaa"
示例 2:
输入: "abcd"
输出: "dcbabcd"
解答
暴力求解最长的回文前缀,但会在最后一个测试样例超时,针对求解,勉强A过
class Solution {
public:
string shortestPalindrome(string s) {
if(isPalindrome(s))
return s;
string result = s;
int l = s.length();
//针对最后一个测试样例
if(l>20000)
{
reverse(s.begin(), s.end());
return s + result.substr((l-2)/2);
}
for(int i=l-1;i>0;i--){
result.insert(l-i-1, 1, s[i]);
if(isPalindrome(result))
break;
}
return result;
}
bool isPalindrome(string& s){
int l = s.length();
for(int i=0;i<l/2;i++){
if(s[i] != s[l-i-1])
return false;
}
return true;
}
};
同样是暴力解法,python
写法简洁很多
class Solution:
def shortestPalindrome(self, s: str) -> str:
if not s:
return ''
n = len(s)
for i in range(n-1, -1, -1):
s1 = s[:i+1]
if s1 == s1[::-1]:
s2 = s[i+1:]
break
return s2[::-1] + s
最后,参考官方题解,将该问题处理成字符串匹配查找问题,即原字符串作为模式串,反转字符串作为查找串,当反转字符串查找到末尾时,模式串对应位置表示回文前缀,使用KMP算法如下:
class Solution {
public:
string shortestPalindrome(string s) {
int n = s.size();
vector<int> fail(n, -1);
for (int i = 1; i < n; ++i) {
int j = fail[i - 1];
while (j != -1 && s[j + 1] != s[i]) {
j = fail[j];
}
if (s[j + 1] == s[i]) {
fail[i] = j + 1;
}
}
int best = -1;
for (int i = n - 1; i >= 0; --i) {
while (best != -1 && s[best + 1] != s[i]) {
best = fail[best];
}
if (s[best + 1] == s[i]) {
++best;
}
}
string add = (best == n - 1 ? "" : s.substr(best + 1, n));
reverse(add.begin(), add.end());
return add + s;
}
};