LeetCode 第5题:最长回文子串
1.LeetCode 第10题:正则表达式匹配2.LeetCode 第1题:两数之和3.LeetCode 第2题:两数相加4.LeetCode 第3题:无重复字符的最长子串5.LeetCode 第4题:寻找两个正序数组的中位数6.LeetCode 第8题:字符串转换整数 (atoi)7.LeetCode 第7题:整数反转8.LeetCode 第6题:Z字形变换
9.LeetCode 第5题:最长回文子串
10.LeetCode 第9题:回文数11.LeetCode 第11题:盛最多水的容器12.LeetCode 第12题:整数转罗马数字13.LeetCode 第13题:罗马数字转整数14.LeetCode 第14题:最长公共前缀15.LeetCode 第15题:三数之和16.LeetCode 第16题:最接近的三数之和17.LeetCode 第17题:电话号码的字母组合18.LeetCode 第18题:四数之和19.LeetCode 第19题:删除链表的倒数第N个结点20.LeetCode 第20题:有效的括号21.LeetCode 第21题:合并两个有序链表22.LeetCode 第22题:括号生成23.LeetCode 第23题:合并K个升序链表24.LeetCode 第24题:两两交换链表中的节点25.LeetCode 第25题:K 个一组翻转链表26.LeetCode 第26题:删除有序数组中的重复项27.LeetCode 第27题:移除元素28.LeetCode 第28题:找出字符串中第一个匹配项的下标29.LeetCode 第29题:两数相除30.LeetCode 第30题:串联所有单词的子串31.LeetCode 第31题:下一个排列32.LeetCode 第32题:最长有效括号33.LeetCode 第33题:搜索旋转排序数组34.LeetCode 第34题:在排序数组中查找元素的第一个和最后一个位置35.LeetCode 第35题:搜索插入位置36.LeetCode 第36题:有效的数独37.LeetCode 第37题:解数独38.LeetCode 第38题:外观数列39.LeetCode 第39题:组合总和40.LeetCode 第40题:组合总和 II41.LeetCode 第41题:缺失的第一个正数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 仅由数字和英文字母组成
解题思路
方法一:中心扩展法
回文串是以中心对称的,可以从每个位置开始,向两边扩展,找到以该位置为中心的最长回文串。
关键点:
- 回文串的中心可能是一个字符,也可能是两个字符
- 需要考虑奇数长度和偶数长度的回文串
- 对每个可能的中心都要尝试扩展
具体步骤:
- 遍历字符串的每个字符作为中心点
- 对每个中心点:
- 尝试奇数长度扩展(一个字符为中心)
- 尝试偶数长度扩展(两个字符为中心)
- 记录最长的回文子串
时间复杂度: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);
}
}
代码详解
中心扩展法:
ExpandAroundCenter
方法:- 从给定的中心向两边扩展
- 返回找到的回文串长度
- 主方法中:
- 对每个位置尝试奇数和偶数长度的扩展
- 更新最长回文串的起始位置和长度
动态规划:
- 初始化:
- 单个字符都是回文
- 检查长度为2的子串
- 状态转移:
- 检查更长的子串
- 使用dp数组记录子串是否为回文
执行结果
中心扩展法:
- 执行用时:76 ms
- 内存消耗:36.5 MB
动态规划:
- 执行用时:124 ms
- 内存消耗:37.8 MB
总结与反思
- 这是一道经典的字符串处理题目,考察了:
- 回文串的性质
- 动态规划的应用
- 中心扩展的思想
- 两种解法比较:
- 中心扩展法实现简单,空间复杂度低
- 动态规划思路清晰,但空间复杂度较高
- 优化思路:
- 可以用Manacher算法进一步优化到线性时间复杂度
- 预处理可以减少边界判断
相关题目
- LeetCode 第516题:最长回文子序列
- LeetCode 第647题:回文子串
- LeetCode 第9题:回文数
- LeetCode 第214题:最短回文串
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了