题目描述:

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".

这道题用直接的双重循环可能会超时,但是也不一定,比如我下面的代码就可以AC:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Solution {
public:
string shortestPalindrome(string s) {
if(s.empty()) return s;
int max_r = INT_MIN;
for (int i = s.length() / 2; i >= 0; i--) {
if ((max_r = palindromeBeside(s, i)) != -1) {
break;
}
}
string t = s.substr(max_r);
reverse(t.begin(), t.end());
return t + s;
}

int palindromeBeside(string &s, int axis) {
int l = axis, r = axis;
for (; l >= 0 && r < s.length(); l--, r++) {
if(s[l] != s[r])
break;
}
if (l < 0) {
return r;
}
l = axis - 1, r = axis;
for (; l >= 0 && r < s.length(); l--, r++) {
if(s[l] != s[r])
break;
}
if (l < 0) {
return r;
}
return -1;
}
};

但是这肯定不是一道Hard题的解法。这道题的本质在于寻找一个字符串S的最长回文前缀子串k,回文串的一个特征就是翻转之后保持不变,如果我们把S整个翻转之后接到S的后面得到的是以k开头,以k结尾的字符串。可以使用KMP算法中计算字符串自我覆盖情况的算法来进行计算,这个算法有点DP的意思,但是理解起来还是有点困难的,具体介绍可以Google关键字KMP。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Solution {
public:
string shortestPalindrome(string s) {
if(s.empty()) return s;
string ts = s;
reverse(ts.begin(), ts.end());
ts = s + "|" + ts;
vector<int> v(ts.length(), 0);
for (int i = 1; i < ts.length(); i++) {
int index = i - 1;
while (index >= 0 && ts[v[index]] != ts[i]) {
index = v[index] - 1;
}
if (index >= 0) {
v[i] = v[index] + 1;
}
}

ts = s.substr(v.back());
reverse(ts.begin(), ts.end());
return ts + s;
}
};