【算法】求解最大回文子字符串

第一种方法:暴力求解,时间复杂度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]
}

猜你喜欢

转载自blog.csdn.net/ll523587181/article/details/81346288