manacher 俗称马拉车算法,也是本文的主角,是一种能够将最长回文串的求解复杂度降低到 O(N) 的一种高效算法,
当我第一次见到求解最长回文串的题目时,首先采用的就是暴力解法,O(N平方) 复杂度遍历所有可能的串,然后再用 O(N) 的时间来求回文串的最大长度,使用 map 存储各个下标对的回文情况尽管能减少一部分计算,
但是显然这种方式时间复杂度过高,部分 case 容易超时
这种算法的大概思路如下:
- 通过插入一些符号简化奇偶个数和边界对判断回文串的干扰
- 中心点的整个边界(除去中心点)的一半恰好等于中心点的最大回文串长度
- 利用大回文串边界内的位置的最大回文串个数以大中心点对称的规律大大简化计算量
本人使用 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 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| func longestPalindrome(s string) string { origin := []byte(s)
if len(origin) == 1 { return s }
var maxCenterIndex int
bs := process(s) p := make([]int, len(bs))
c := 0 r := 0
for i:=1;i<len(bs)-1;i++{ mirror := 2*c-i
if r > i { if r-i > p[mirror] { p[i] = p[mirror] } else { p[i] = r-i } }
for bs[p[i]+i+1] == bs[i-p[i]-1] { p[i]++ }
if i+p[i] > r { r = i+p[i] c = i }
if p[maxCenterIndex] < p[i] { maxCenterIndex = i } }
mx := p[maxCenterIndex]
startIndex := (maxCenterIndex - 1) / 2 - mx/2 endIndex := startIndex + mx return string(origin[startIndex:endIndex]) }
func process(s string) []byte { bs := []byte(s) var buffer bytes.Buffer buffer.WriteString("^") for _,b := range bs { buffer.WriteString("#") buffer.WriteByte(b) } buffer.WriteString("#$") return buffer.Bytes() }
|