题目:给定一段字符串,求该其最长的回文子串
主要思路:
-
我们创建一个将目标字符穿进行扩充,然后使用
#
进行填充,并在前后分别添加^
和$
方便后续操作 -
再创建一个数组
T
记录当前节点的半径如何构造?假设当前该设置下标为
i
的值了,i
的左边有一个下标c
的,其半径能到达的最右边为当前最大那么,如果
i
关于c
对称的点在c
的半径里面,那么i
的半径一定大于等于其对称点的半径,即可以设置为对称点的半径,如果不在,就先假设当前i
的半径为0然后我们再对
i
加上当前已知i
半径的左右比较,如果相等则将T[i]
+1,反之就已经找到当前半径最大构造完之后如下,这里的目标字符串为
aba
,比如:我在构造
i=4
的时候,也就是如下的b
点时,当前的中心为a
,其a
的半径为1,即右边最大可达3,是小于当前b
的下标的,所以T[4]=0
,然后再向b
的左右遍历,直到T[4]=3
的时候,不再对称,退出
代码实现:
// 获得s的最长回文子串长度
func Manacher(s string) int {
str := "^#"
for _, v := range s {
str += string(v)
str += "#"
}
str += "$"
T := make([]int, len(str)) // 保存当前节点的半径长
center := 0
maxRadius := 0
maxLen := 0
for i := 1; i < len(str)-1; i++ {
// 在当前最长的范围内
if i < center+maxRadius {
// 寻找对称的左边点,但也有可能右边没那么长,所以取最小
T[i] = min(T[center*2-i], center+maxRadius-i)
}
// 对应右边一个和左边一个比较,因为最后一个一定不匹配,所以这不用担心指针溢出
for str[i+T[i]+1] == str[i-T[i]-1] {
T[i]+=1
}
// 如果当前的右边的临界比原来的大,
if i+T[i] > center+maxRadius {
nowLen := maxRadius
if nowLen > maxLen {
maxLen = nowLen
}
center = i
maxRadius = T[i]
}
}
return maxLen
}
func min(x, y int) int {
if x < y {
return x
}
return y
}
时间复杂度:
O
(
n
2
)
O(n^2)
O(n2)