0%

最短回文串

题目(LeetCode #214)

给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。

示例 1:

输入: “aacecaaa”
输出: “aaacecaaa”

示例 2:

输入: “abcd”
输出: “dcbabcd”

题解

可利用Manacher 算法找到原字符串包含第一个字符的最长回文子串,将该回文子串后的字符逆序加到开头即可。

示例 1 中,对 aacecaaa 来说,包含第一个字符的最长回文子串为 aacecaa ,需把剩余的 a 逆序加到开头,即得到 aaacecaaa ;示例 2 中,abcd 包含第一个字符的最长回文子串为 abcd 逆序得到 dcb ,放到开头即得到 dcbabcd

Java

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
36
37
38
39
40
41
42
43
44
45
46
47
public class ShortestPalindrome {
public static String preprocess(String s) {
String result = "^";
for (int i = 0; i < s.length(); i++) {
result += "#" + s.charAt(i);
}

return result + "#$";
}

public static String shortestPalindrome(String s) {
if (s == null || s.length() == 0) return "";

String tmpStr = preprocess(s);
int strLen = tmpStr.length();
int C = 0, R = 0;
int[] p = new int[strLen];
int maxLen = 0;

for (int i = 1; i < strLen - 1; i++) {
p[i] = R > i ? Math.min(p[2 * C - i], R - i) : 1;

while (tmpStr.charAt(i - p[i]) == tmpStr.charAt(i + p[i])) {
p[i]++;
}

if (R < p[i] + i) {
R = p[i] + i;
C = i;
}

// 仅保存以第一个字符开头的回文子串的最大长度
// (C - p[C]) / 2 即为当前回文串的起始索引
if (maxLen < p[i] - 1 && (C - p[C]) / 2 == 0) {
maxLen = p[i] - 1;
}
}

// 逆序剩余部分字符串
String result = "";
for (int i = s.length() - 1; i >= maxLen; i--) {
result += s.charAt(i);
}

return result + s;
}
}

Python

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class ShortestPalindrome:
def shortest_palindrome(self, s: str) -> str:
tmp_str = "^#" + "".join([x + "#" for x in s]) + "$"
str_len = len(tmp_str)
p = [0] * str_len
c, r = 0, 0
max_len = 0

for i in range(1, str_len - 1):
p[i] = min(p[2 * c - i], r - i) if r > i else 1
while tmp_str[i - p[i]] == tmp_str[i + p[i]]:
p[i] += 1

if r < p[i] + i:
r = p[i] + i
c = i

if max_len < p[i] - 1 and (c - p[c]) // 2 == 0:
max_len = p[i] - 1

return "".join([x for x in s[:max_len - 1:-1]]) + s

Go

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
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
func preprocess(s string) string {
result := "^#"

for _, ch := range s {
result += string(ch) + "#"
}

return result + "$"
}

func shortestPalindrome(s string) string {
if len(s) == 0 {
return ""
}

tmpStr := preprocess(s)
strLen := len(tmpStr)
p := make([]int, strLen)
C, R := 0, 0
maxLen := 0

for i := 1; i < strLen-1; i++ {
if R > i {
p[i] = min(p[2*C-i], R-i)
} else {
p[i] = 1
}

for tmpStr[i-p[i]] == tmpStr[i+p[i]] {
p[i]++
}

if R < p[i]+i {
R = p[i] + i
C = i
}

if maxLen < p[i]-1 && (C-p[C])/2 == 0 {
maxLen = p[i] - 1
}
}

result := ""
for i := len(s) - 1; i >= maxLen; i-- {
result += string(s[i])
}

return result + s
}

func min(a, b int) int {
if a < b {
return a
}
return b
}