给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。
示例 1:
输入:s = “aacecaaa”
输出:“aaacecaaa”
示例 2:
输入:s = “abcd”
输出:“dcbabcd”
提示:
0 <= s.length <= 5 * 104
s 仅由小写英文字母组成
解题思路:
本质是求最长的回文前缀。可以暴力枚举每一个点。也可以用kmp算法求解:
暴力:
class Solution {
public:
string shortestPalindrome(string s) {
//1. 找到以第一个字符为头的最长回文字符串。如果已经是回文则直接返回。
int n = s.size();
int len = 0;
auto ispalind = [&](int end) {
int begin = 0;
while (begin < end) {
if (s[begin++] != s[end--]) return false;
}
return true;
};
for (int i = 0; i < n; ++i) {
if (s[0] == s[i] && ispalind(i)) len = i + 1;
}
if (len == n) return s;
string res = s.substr(len, n - len);
reverse(res.begin(), res.end());
res += s;
return res;
}
};
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;
}
};