题目:
Given a string S, you are allowed to convert it to a palindrome by adding characters in front of it. Find and return the shortest palindrome you can find by performing this transformation.
For example:
Given “aacecaaa”, return “aaacecaaa”.
Given “abcd”, return “dcbabcd”.
题意:
给定一个字符串,通过在其前面加上一些字符,使其成为一个回文串。找出最小的回文串。
思路:
首先知道回文串有个很大的特点,就是回文串反过来之后跟自己还是相等的。比如s是回文串”aba”,那么s字符串反过来之后还是”aba”.
对于现在的一个字符串s,我们可以把s分成两个部分,第一个部分是前面最长的回文串s1,后面一部分是s2,那么只要把s2的逆串加到s的前面,就可以形成s2’+s1+s2,这样就形成了一个回文串。所以就是需要找到s前面最长的那部分回文串s1。
现在问题简化为找s前面的s1的回文串。正如前面所说,如果s1是回文串,s1’是s1的逆序串,那么s1 = s1’。如前面所说s = s1 + s2,那么s’(逆串) = s2’ + s1’,如果把s与s’串在一起,那么就变成了s1 + s2 + s2’ + s1’,并且此处s1=s1’,回想我们的KMP算法,next的求法不就是找一个字符串的前面一部分与后面一部分相等的部分么。所以可以使用KMP的算法找出拼接起来的串s1 + s2 + s2’ + s1’最前面与最后面相等的串,即找出s1。但是我们需要在s与s’中间加一个分开符”#”,用来将避免出现求的s1超过s的长度。比如s=”aaa”,那么s’=”aaa”,这个时候算出的s1会变成”aaaaaa”,加上”#”后算”aaa#aaa”得到的s1就只会是”aaa”了。
以上所述。
代码如下:
class Solution {
public:
string shortestPalindrome(string s) {
if(s.empty())return s;
string s_reverse = s;
reverse(s_reverse.begin(), s_reverse.end());
string temp = s + "#" + s_reverse;
vector<int> next(temp.size() + 1, 0);
next[0] = - 1;
next[1] = 0;
for(int i = 2; i < temp.size() + 1; i++) {
int p = next[i-1];
while(p != -1 && temp[p] != temp[i - 1]) {
p = next[p];
}
next[i] = p + 1;
}
return s_reverse.substr(0, s_reverse.size() - next[temp.size()]) + s;
}
};