第一种方法:暴力求解,时间复杂度O(n^3)
两个嵌套循环遍历字符串中的所有子字符串,另一个循环用来判断当前子字符串是否为回文。
func Longestpalindromicstring_On3(s string) string {
length := 0
var str string
for i := 0; i < len(s); i++ {
for j := i; j < len(s); j++ {
sli := s[i : j+1]
ispalindromic := true
for k := 0; k < len(sli)/2; k++ {
if sli[k] != sli[len(sli)-k-1] {
ispalindromic = false
}
}
if ispalindromic == true {
if len(sli) > length {
length = len(sli)
str = sli
}
}
}
}
return str
}
第二种方法:采用对于字符串中常用start/end或者是low/high前后遍历法。时间复杂度为O(n^2)
将子字符串的长度分为单数和双数,分别进行不同的赋值。
遍历0:len(s)-1,如果是单数,low=high=index;如果是双数:low=index, high= index+1
func Longestpalindromicstring_On2(s string) string {
var str string
length := 0
for i := 0; i < len(s)-1; i++ {
// 将字符串分为单核和双核
str1 := search_On2(s, i, i)
str2 := search_On2(s, i, i+1)
if len(str1) > len(str2) && length < len(str1) {
str = str1
length = len(str1)
} else if len(str2) > len(str1) && length < len(str2) {
str = str2
length = len(str2)
}
}
return str
}
func search_On2(s string, low, high int) string {
for low >= 0 && high < len(s) && s[low] == s[high] {
low = low - 1
high = high + 1
}
return s[low+1 : high]
}
第三种方法:Manacher算法
重在理解构造数组length,length[i]是以当前位置为中心,周围回文字符串半径。
算法首先将字符串都变成单数。即向中间以及首末插入类似#符号。则cbbd变成#c#b#b#d#
其中使用到两个变量,sub_mid是在i之前最长回文子字符串的中心,sub_side是length(sub_mid) + sub_mid-1,也就是最长回文子字符串的最右端点。初始值均置0。
每次遍历时判断当前i与sub_side的关系,若是小于sub_side,则i在最大回文子字符串里,根据sub_mid寻找到其对称的点,将对称点的length数组的值作为length[i]的值。否则前后遍历字符串计算其length值。每次循环都更新sub_mid和sub_side。
上述cbbd字符串对应的length数组为[1,2,1,2,3,2,1,2,1]。
func Longestpalindromicstring_On(s string) string {
// 重在构造length数组
var str []byte
for i := 0; i < len(s); i++ {
str = append(str, '#')
str = append(str, s[i])
}
str = append(str, '#')
var length []int = make([]int, len(str))
sub_mid, sub_side := 0, 0
maxlength, index := 0, 0
for i := 0; i < len(str); i++ {
if i < sub_side {
if length[2*sub_mid-i] > sub_side-i+1 {
length[i] = sub_side - i + 1
} else {
length[i] = length[2*sub_mid-i]
}
} else {
for i-length[i] >= 0 && i+length[i] < len(str) && str[i-length[i]] == str[i+length[i]] {
length[i]++
}
}
if length[i]+i-1 > sub_side {
sub_side = length[i] + i - 1
sub_mid = i
}
if maxlength < length[i] {
maxlength = length[i]
index = i
}
}
return s[(index-length[index]+1)/2 : (index+length[index])/2]
}