5. 最长回文子串

57 阅读2分钟

题目

leetcode 给你一个字符串 s,找到 s 中最长的 回文子串。

代码

package main  
  
import "fmt"  
  
func longestPalindrome(s string) string {  
   if len(s) == 0 || len(s) == 1 {  
      return s  
   }  
  
   start, end := 0, 1  
   for i := 0; i < len(s); i++ {  
      len1 := expend(s, i, i)  
      len2 := expend(s, i, i+1)  
      maxLen := max(len1, len2)  
      if maxLen > end-start {  
         start = i - (maxLen-1)/2  
         end = i + maxLen 
      }  
   }  
   return s[start:end]  
}  
  
func expend(s string, left int, right int) int {  
   for left >= 0 && right < len(s) && s[left] == s[right] {  
      left--  
      right++  
   }  
   return right - left - 1  
}  
  
func max(a int, b int) int {  
   if a > b {  
      return a  
   }  
   return b  
}  
  
func main() {  
   s := "babad"  
   fmt.Println(longestPalindrome(s))  
}

解题思路

  1. 首先关于回文子串, 通用的解法就是以单字符和双字符分别向两边扩展, 分别找到最长的长度, 比较两者的最大值, 然后和全局的最大长度比较, 记录下全局的最大长度, 最后返回
  2. 本题的代码分析, 首先先判断特殊情况, 以免后面代码判断复杂
  3. 设定初始值, 即 start为0, end为1, 第一个字符肯定是回文子串
  4. 然后从头开始遍历, 看单字符和双字符扩展起来, 哪个得到的回文子串长就取哪个
  5. 难点1, expend的返回 right - left - 1, 这里返回回文子串的长度, 特别像这种表达式, 可以举个特例, 比如得到子串是 bab, 那么此时left是-1, right是3, 长度是3, 那么怎么返回3呢, 就是 3 - (-1) - 1, 这样就很容易得到表达式
  6. 难点2, longestPalindrome中根据长度和i得到start和end, 也是通过举个特例来得到表达式, 还是子串是 bab, 也就是maxLen是3, 此时i为1, 我们需要start为0, end为2, 怎么通过maxLen和i得到start和end呢, 简单的逻辑思考下, 就能得出 start = 1 - (3 - 1) / 2, 也就是 start = i - (maxLen-1)/2, 然后就更简单了, 直接 end = start + manLen 就行了

总结

回文子串都能通过单字符和双字符向两边扩展的方式解决, 技巧就是先处理特殊情况, 然后记录全局长度, 以及表达式的推导