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最大的回文串,该回文串的特点,左边界与S左边界同。
故问题转化为,求出该回文串的右边界。
然后将右边界后面的字符反转加到S前面,即为题目所求。
由于回文串的特点为,反转后,得到的新串与原串相等。
则将S串,整体反转后得到一个新串RS。
则题目进一步转化为,求S串的最大前缀,且该前缀与RS的后缀相等。
在leetcode上实际执行时间为96ms。
class Solution {
public:
string shortestPalindrome(string s) {
string rev(s.rbegin(), s.rend());
int size = s.size();
for (; size > 0; --size) {
if (s.substr(0, size) == rev.substr(rev.size()-size, size))
break;
}
return rev.substr(0, rev.size()-size) + s;
}
};
算法二,KMP前缀法
算法一,其实不够效率。
求出最大的 前缀且与后缀相等,可以寻求KMP帮助。
KMP建立next数组过程,就是一个不断求出当前子串中,最大的前缀和后缀相等问题。
这里,我们S字符串,和其反转后得到新字符串RS,并在中间加入一个分隔字符,合并成一个新的字符串。从而问题就可以用KMP方法解决。
之所以加入分隔字符,是为了防止前缀和后缀有重叠部分。
此处,我们所感兴趣的next数组中最后一个值。
即,合并后的新串中,最大前缀与后缀的长度。
在leetcode上实际执行时间为16ms。远好于算法一。
class Solution {
public:
string shortestPalindrome(string s) {
if (s.empty()) return s;
string kmp = s + "#" + string(s.rbegin(), s.rend());
vector<int> next(kmp.size()+1);
int j = -1;
next[0] = j;
for (int i=0; i<kmp.size();) {
while (j>=0 && kmp[i]!=kmp[j])
j = next[j];
++i;
++j;
next[i] = j;
}
string suffix = s.substr(next.back());
return string(suffix.rbegin(), suffix.rend()) + s;
}
};