LeetCode 第5题:最长回文子串

LeetCode 第5题:最长回文子串

题目描述

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

难度

中等

题目链接

https://leetcode.cn/problems/longest-palindromic-substring/

示例

示例 1:

输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。

示例 2:

输入:s = "cbbd"
输出:"bb"

提示

  • 1 <= s.length <= 1000
  • s 仅由数字和英文字母组成

解题思路

方法一:中心扩展法

回文串是以中心对称的,可以从每个位置开始,向两边扩展,找到以该位置为中心的最长回文串。

关键点:

  1. 回文串的中心可能是一个字符,也可能是两个字符
  2. 需要考虑奇数长度和偶数长度的回文串
  3. 对每个可能的中心都要尝试扩展

具体步骤:

  1. 遍历字符串的每个字符作为中心点
  2. 对每个中心点:
    • 尝试奇数长度扩展(一个字符为中心)
    • 尝试偶数长度扩展(两个字符为中心)
  3. 记录最长的回文子串

时间复杂度:O(n²)
空间复杂度:O(1)

方法二:动态规划

使用动态规划可以避免重复计算。定义dp[i][j]表示s[i..j]是否为回文串。

状态转移方程:

  • dp[i][j] = (s[i] == s[j]) && (j - i < 3 || dp[i+1][j-1])

代码实现

C# 实现(中心扩展法)

public class Solution {
    public string LongestPalindrome(string s) {
        if (string.IsNullOrEmpty(s)) return "";
      
        int start = 0, maxLength = 0;
      
        for (int i = 0; i < s.Length; i++) {
            // 尝试奇数长度的回文串
            int len1 = ExpandAroundCenter(s, i, i);
            // 尝试偶数长度的回文串
            int len2 = ExpandAroundCenter(s, i, i + 1);
          
            // 更新最长回文串的信息
            int len = Math.Max(len1, len2);
            if (len > maxLength) {
                maxLength = len;
                start = i - (len - 1) / 2;
            }
        }
      
        return s.Substring(start, maxLength);
    }
  
    private int ExpandAroundCenter(string s, int left, int right) {
        // 从中心向两边扩展,直到不能形成回文
        while (left >= 0 && right < s.Length && s[left] == s[right]) {
            left--;
            right++;
        }
        // 返回回文串的长度
        return right - left - 1;
    }
}

C# 实现(动态规划)

public class Solution {
    public string LongestPalindrome(string s) {
        int n = s.Length;
        bool[,] dp = new bool[n, n];
        int maxLength = 1;
        int start = 0;
      
        // 所有单个字符都是回文
        for (int i = 0; i < n; i++) {
            dp[i, i] = true;
        }
      
        // 检查长度为2的子串
        for (int i = 0; i < n - 1; i++) {
            if (s[i] == s[i + 1]) {
                dp[i, i + 1] = true;
                start = i;
                maxLength = 2;
            }
        }
      
        // 检查长度大于2的子串
        for (int len = 3; len <= n; len++) {
            for (int i = 0; i <= n - len; i++) {
                int j = i + len - 1;
                if (s[i] == s[j] && dp[i + 1, j - 1]) {
                    dp[i, j] = true;
                    if (len > maxLength) {
                        start = i;
                        maxLength = len;
                    }
                }
            }
        }
      
        return s.Substring(start, maxLength);
    }
}

代码详解

中心扩展法:

  1. ExpandAroundCenter方法:
    • 从给定的中心向两边扩展
    • 返回找到的回文串长度
  2. 主方法中:
    • 对每个位置尝试奇数和偶数长度的扩展
    • 更新最长回文串的起始位置和长度

动态规划:

  1. 初始化:
    • 单个字符都是回文
    • 检查长度为2的子串
  2. 状态转移:
    • 检查更长的子串
    • 使用dp数组记录子串是否为回文

执行结果

中心扩展法:

  • 执行用时:76 ms
  • 内存消耗:36.5 MB

动态规划:

  • 执行用时:124 ms
  • 内存消耗:37.8 MB

总结与反思

  1. 这是一道经典的字符串处理题目,考察了:
    • 回文串的性质
    • 动态规划的应用
    • 中心扩展的思想
  2. 两种解法比较:
    • 中心扩展法实现简单,空间复杂度低
    • 动态规划思路清晰,但空间复杂度较高
  3. 优化思路:
    • 可以用Manacher算法进一步优化到线性时间复杂度
    • 预处理可以减少边界判断

相关题目

  • LeetCode 第516题:最长回文子序列
  • LeetCode 第647题:回文子串
  • LeetCode 第9题:回文数
  • LeetCode 第214题:最短回文串
posted @   旧厂街小江  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示