【LeetCode】5. 最长回文子串

leetcode

 

以下是使用 ​​中心扩展法​​ 实现的最长回文子串解决方案,时间复杂度为 O(n²),空间复杂度为 O(1),适合处理中等规模的字符串:

func longestPalindrome(s string) string {
    if len(s) == 0 {
        return ""
    }
    start, end := 0, 0
    for i := 0; i < len(s); i++ {
        // 处理奇数长度回文(如 "aba")
        l1, r1 := expand(s, i, i)
        // 处理偶数长度回文(如 "abba")
        l2, r2 := expand(s, i, i+1)
        // 更新最长回文边界
        if r1 - l1 > end - start {
            start, end = l1, r1
        }
        if r2 - l2 > end - start {
            start, end = l2, r2
        }
    }
    return s[start:end+1]
}

// 从中心向两边扩展,返回回文的最左/右边界
func expand(s string, left, right int) (int, int) {
    for left >= 0 && right < len(s) && s[left] == s[right] {
        left--
        right++
    }
    // 回退到最后一个满足条件的边界
    return left + 1, right - 1
}

算法说明

  1. ​​核心思想​​
    遍历每个可能的回文中心(每个字符和每两个字符中间的位置),向两侧扩展检测回文。 

    • ​​奇数长度回文​​:以单个字符为中心(如 "aba" 以 'b' 为中心)
    • ​​偶数长度回文​​:以两个字符中间为中心(如 "abba" 以中间两个 'b' 为中心)
  2. ​​复杂度分析​​

    • ​​时间复杂度​​:O(n²),遍历每个中心点 O(n),每个中心扩展 O(n)
    • ​​空间复杂度​​:O(1),仅使用常数级额外空间
  3. ​​关键优化点​​

    • 直接返回字符串切片 s[start:end+1],避免额外内存分配
    • 统一处理奇偶两种回文类型,减少代码重复

测试示例

func main() {
    fmt.Println(longestPalindrome("babad")) // 输出 "bab" 或 "aba"
    fmt.Println(longestPalindrome("cbbd"))  // 输出 "bb"
    fmt.Println(longestPalindrome("a"))     // 输出 "a"
}

扩展:Manacher 算法(O(n) 时间复杂度)

若需要处理超长字符串(例如长度超过 10^4),可使用 ​​Manacher 算法​​。该算法通过预处理字符串和利用对称性减少重复计算,但实现较复杂:

func longestPalindromeManacher(s string) string {
    if len(s) < 2 {
        return s
    }
    // 预处理:插入特殊字符 '#'
    newS := make([]rune, 0)
    newS = append(newS, '#')
    for _, c := range s {
        newS = append(newS, c)
        newS = append(newS, '#')
    }
    // 计算每个位置的回文半径
    dp := make([]int, len(newS))
    maxRight, center, maxLen, begin := 0, 0, 1, 0
    for i := 0; i < len(newS); i++ {
        if i < maxRight {
            dp[i] = min(maxRight-i, dp[2*center-i])
        }
        left, right := i-(1+dp[i]), i+(1+dp[i])
        for left >= 0 && right < len(newS) && newS[left] == newS[right] {
            dp[i]++
            left--
            right++
        }
        if i+dp[i] > maxRight {
            maxRight = i + dp[i]
            center = i
        }
        if dp[i] > maxLen {
            maxLen = dp[i]
            begin = (i - maxLen) / 2
        }
    }
    return s[begin : begin+maxLen]
}

func min(a, b int) int {
    if a < b {
        return a
    }
    return b
}

方法对比

方法时间复杂度空间复杂度适用场景
中心扩展法 O(n²) O(1) 一般长度字符串
Manacher算法 O(n) O(n) 超长字符串(1e5+)

可根据实际需求选择实现方式。中心扩展法更简洁,Manacher 算法适合高性能场景。 

posted @ 2025-04-24 16:20  云隙之间  阅读(43)  评论(0)    收藏  举报