5.Longest Palindromic Substring

Given a string s, find the longest palindromic substring in s.

Example:

Input: s = "babad"

Output: "bab"

Algorithm:

  1. Initialize a 2D array dp of size m x n, where m is the length of the input string s and n is the maximum length of a palindromic substring.
  2. Iterate through the input string s and for each character c, check if it is the same as the previous character c-1. If it is, mark the corresponding cell in dp as true.
  3. Iterate through the input string s and for each character c, check if it is the same as the next character c+1. If it is, mark the corresponding cell in dp as true.
  4. Iterate through the 2D array dp and find the longest palindromic substring.

Code:

// 动态规划
func longestPalindrome(s string) string {
    
	    // 长度为1 肯定是回文串
	if len(s) <= 1 {
		return s
	}
    
	// start 代表回文串开始下标,end 代表结束下标
	var start, maxLen, length = 0, 1, len(s)
    
	// 二维数组dp[i][j] 表示索引 i 到索引 j 是否回文,true 是,否则不是
	var dp = make([][]bool, len(s))
     
	 // 长度为 1 的肯定是回文, 所有的 dp[i][i] 都是 true
	 for i := 0; i < length; i++ {
	 	// 初始化数组
	 	dp[i] = make([]bool, length)
	 	dp[i][i] = true
	 }
     
	 // i,j 是回文左右下标,k 是中间回文子串长度
	 // 回文判断规则:s[i]=s[j] 其中 j = i+中间回文子串长度,由于从0开始遍历,下标需要减1
	 // 边界情况:
	 // k长度为2,中间子串长度0也是回文
	 // 中间子串下标规则 dp[i+1][j-1]
	 // 由于 k 长度 1 都是回文,从长度 2 开始遍历
	 for k := 2; k <= length; k++ {
	 	for i := 0; i <= length-k; i++ {
	 		j := i + k - 1
	 		if s[i] == s[j] && (k == 2 || dp[i+1][j-1]) {
	 			dp[i][j] = true
	 			// 更新回文子串长度
	 			if k > maxLen {
	 				start = i
	 				maxLen = k
	 			}
	 		}
	 	}
	 }
	 return s[start : start+maxLen]
}

中心扩展法


// 中心扩展
func longestPalindrome1(s string) string {
    
	 if len(s) < 2 {
	 	return s
	 }
	 // 起始位置、结束位置
	 start, end := 0, 0
	 for i := 0; i < len(s); i++ {
	 	// 以一个字符中心扩展
	 	exp1 := expand(s, i, i)
	 	// 以两个字符中心扩展
	 	exp2 := expand(s, i, i+1)
	 	maxLen := max(exp1, exp2)
	 	// 在每次扩展后,我们比较当前回文串的长度和已知的最长回文子串长度,
	 	// 如果大于最长回文子串长度,则更新最长回文子串的起始位置和结束位置。
	 	if maxLen > end-start+1 {
	 		// 起始位置=当前位置i - (maxLen-1)/2
	 		start = i - (maxLen-1)/2
	 		// 结束位置=当前位置i + maxLen/2
	 		end = i + maxLen/2
	 	}
	 }
	 return s[start : end+1]
}

 func expand(s string, left, right int) int {
 	for left >= 0 && right < len(s) && s[left] == s[right] {
 		left--
 		right++
 	}
 	// 因为扩展时左右边界都多扩展了一步
 	return right - left - 1
 }
 
 func max(a, b int) int {
 	if a > b {
 		return a
 	}
 	return b
 }